1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
17 #include "libgame/libgame.h"
24 #define CHUNK_ID_LEN 4 /* IFF style chunk id length */
25 #define CHUNK_SIZE_UNDEFINED 0 /* undefined chunk size == 0 */
26 #define CHUNK_SIZE_NONE -1 /* do not write chunk size */
27 #define FILE_VERS_CHUNK_SIZE 8 /* size of file version chunk */
28 #define LEVEL_HEADER_SIZE 80 /* size of level file header */
29 #define LEVEL_HEADER_UNUSED 14 /* unused level header bytes */
30 #define LEVEL_CHUNK_CNT2_SIZE 160 /* size of level CNT2 chunk */
31 #define LEVEL_CHUNK_CNT2_UNUSED 11 /* unused CNT2 chunk bytes */
32 #define TAPE_HEADER_SIZE 20 /* size of tape file header */
33 #define TAPE_HEADER_UNUSED 3 /* unused tape header bytes */
35 /* file identifier strings */
36 #define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
37 #define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
38 #define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
41 /* ========================================================================= */
42 /* level file functions */
43 /* ========================================================================= */
45 static void setLevelInfoToDefaults()
49 level.file_version = FILE_VERSION_ACTUAL;
50 level.game_version = GAME_VERSION_ACTUAL;
52 level.encoding_16bit_field = FALSE; /* default: only 8-bit elements */
53 level.encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
54 level.encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
56 lev_fieldx = level.fieldx = STD_LEV_FIELDX;
57 lev_fieldy = level.fieldy = STD_LEV_FIELDY;
59 for(x=0; x<MAX_LEV_FIELDX; x++)
60 for(y=0; y<MAX_LEV_FIELDY; y++)
61 Feld[x][y] = Ur[x][y] = EL_SAND;
64 level.gems_needed = 0;
65 level.amoeba_speed = 10;
66 level.time_magic_wall = 10;
67 level.time_wheel = 10;
68 level.time_light = 10;
69 level.time_timegate = 10;
70 level.amoeba_content = EL_DIAMOND;
71 level.double_speed = FALSE;
72 level.gravity = FALSE;
73 level.em_slippery_gems = FALSE;
75 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
77 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
78 level.author[i] = '\0';
80 strcpy(level.name, NAMELESS_LEVEL_NAME);
81 strcpy(level.author, ANONYMOUS_NAME);
83 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
86 level.num_yam_contents = STD_ELEMENT_CONTENTS;
87 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
90 level.yam_content[i][x][y] =
91 (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
93 Feld[0][0] = Ur[0][0] = EL_PLAYER1;
94 Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
95 Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_EXIT_CLOSED;
97 BorderElement = EL_STEELWALL;
99 /* try to determine better author name than 'anonymous' */
100 if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
102 strncpy(level.author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
103 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
107 switch (LEVELCLASS(leveldir_current))
109 case LEVELCLASS_TUTORIAL:
110 strcpy(level.author, PROGRAM_AUTHOR_STRING);
113 case LEVELCLASS_CONTRIBUTION:
114 strncpy(level.author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN);
115 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
118 case LEVELCLASS_USER:
119 strncpy(level.author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
120 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
124 /* keep default value */
129 level.no_level_file = FALSE;
132 static int checkLevelElement(int element)
134 if (element >= NUM_FILE_ELEMENTS)
136 Error(ERR_WARN, "invalid level element %d", element);
137 element = EL_CHAR_QUESTION;
139 else if (element == EL_PLAYER_OBSOLETE)
140 element = EL_PLAYER1;
141 else if (element == EL_KEY_OBSOLETE)
147 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
149 level->file_version = getFileVersion(file);
150 level->game_version = getFileVersion(file);
155 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
159 lev_fieldx = level->fieldx = fgetc(file);
160 lev_fieldy = level->fieldy = fgetc(file);
162 level->time = getFile16BitBE(file);
163 level->gems_needed = getFile16BitBE(file);
165 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
166 level->name[i] = fgetc(file);
167 level->name[MAX_LEVEL_NAME_LEN] = 0;
169 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
170 level->score[i] = fgetc(file);
172 level->num_yam_contents = STD_ELEMENT_CONTENTS;
173 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
176 level->yam_content[i][x][y] = checkLevelElement(fgetc(file));
178 level->amoeba_speed = fgetc(file);
179 level->time_magic_wall = fgetc(file);
180 level->time_wheel = fgetc(file);
181 level->amoeba_content = checkLevelElement(fgetc(file));
182 level->double_speed = (fgetc(file) == 1 ? TRUE : FALSE);
183 level->gravity = (fgetc(file) == 1 ? TRUE : FALSE);
184 level->encoding_16bit_field = (fgetc(file) == 1 ? TRUE : FALSE);
185 level->em_slippery_gems = (fgetc(file) == 1 ? TRUE : FALSE);
187 ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
192 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
196 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
197 level->author[i] = fgetc(file);
198 level->author[MAX_LEVEL_NAME_LEN] = 0;
203 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
207 int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
208 int chunk_size_expected = header_size + content_size;
210 /* Note: "chunk_size" was wrong before version 2.0 when elements are
211 stored with 16-bit encoding (and should be twice as big then).
212 Even worse, playfield data was stored 16-bit when only yamyam content
213 contained 16-bit elements and vice versa. */
215 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
216 chunk_size_expected += content_size;
218 if (chunk_size_expected != chunk_size)
220 ReadUnusedBytesFromFile(file, chunk_size);
221 return chunk_size_expected;
225 level->num_yam_contents = fgetc(file);
229 /* correct invalid number of content fields -- should never happen */
230 if (level->num_yam_contents < 1 ||
231 level->num_yam_contents > MAX_ELEMENT_CONTENTS)
232 level->num_yam_contents = STD_ELEMENT_CONTENTS;
234 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
237 level->yam_content[i][x][y] =
238 checkLevelElement(level->encoding_16bit_field ?
239 getFile16BitBE(file) : fgetc(file));
243 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
246 int chunk_size_expected = level->fieldx * level->fieldy;
248 /* Note: "chunk_size" was wrong before version 2.0 when elements are
249 stored with 16-bit encoding (and should be twice as big then).
250 Even worse, playfield data was stored 16-bit when only yamyam content
251 contained 16-bit elements and vice versa. */
253 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
254 chunk_size_expected *= 2;
256 if (chunk_size_expected != chunk_size)
258 ReadUnusedBytesFromFile(file, chunk_size);
259 return chunk_size_expected;
262 for(y=0; y<level->fieldy; y++)
263 for(x=0; x<level->fieldx; x++)
264 Feld[x][y] = Ur[x][y] =
265 checkLevelElement(level->encoding_16bit_field ?
266 getFile16BitBE(file) : fgetc(file));
270 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
274 int num_contents, content_xsize, content_ysize;
275 int content_array[MAX_ELEMENT_CONTENTS][3][3];
277 element = checkLevelElement(getFile16BitBE(file));
278 num_contents = fgetc(file);
279 content_xsize = fgetc(file);
280 content_ysize = fgetc(file);
281 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
283 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
286 content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
288 /* correct invalid number of content fields -- should never happen */
289 if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
290 num_contents = STD_ELEMENT_CONTENTS;
292 if (element == EL_YAMYAM)
294 level->num_yam_contents = num_contents;
296 for(i=0; i<num_contents; i++)
299 level->yam_content[i][x][y] = content_array[i][x][y];
301 else if (element == EL_BD_AMOEBA)
303 level->amoeba_content = content_array[0][0][0];
307 Error(ERR_WARN, "cannot load content for element '%d'", element);
313 void LoadLevel(int level_nr)
315 char *filename = getLevelFilename(level_nr);
316 char cookie[MAX_LINE_LEN];
317 char chunk_name[CHUNK_ID_LEN + 1];
321 /* always start with reliable default values */
322 setLevelInfoToDefaults();
324 if (!(file = fopen(filename, MODE_READ)))
326 level.no_level_file = TRUE;
328 Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
332 getFileChunkBE(file, chunk_name, NULL);
333 if (strcmp(chunk_name, "RND1") == 0)
335 getFile32BitBE(file); /* not used */
337 getFileChunkBE(file, chunk_name, NULL);
338 if (strcmp(chunk_name, "CAVE") != 0)
340 Error(ERR_WARN, "unknown format of level file '%s'", filename);
345 else /* check for pre-2.0 file format with cookie string */
347 strcpy(cookie, chunk_name);
348 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
349 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
350 cookie[strlen(cookie) - 1] = '\0';
352 if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
354 Error(ERR_WARN, "unknown format of level file '%s'", filename);
359 if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
361 Error(ERR_WARN, "unsupported version of level file '%s'", filename);
366 /* pre-2.0 level files have no game version, so use file version here */
367 level.game_version = level.file_version;
370 if (level.file_version < FILE_VERSION_1_2)
372 /* level files from versions before 1.2.0 without chunk structure */
373 LoadLevel_HEAD(file, LEVEL_HEADER_SIZE, &level);
374 LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
382 int (*loader)(FILE *, int, struct LevelInfo *);
386 { "VERS", FILE_VERS_CHUNK_SIZE, LoadLevel_VERS },
387 { "HEAD", LEVEL_HEADER_SIZE, LoadLevel_HEAD },
388 { "AUTH", MAX_LEVEL_AUTHOR_LEN, LoadLevel_AUTH },
389 { "CONT", -1, LoadLevel_CONT },
390 { "BODY", -1, LoadLevel_BODY },
391 { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
395 while (getFileChunkBE(file, chunk_name, &chunk_size))
399 while (chunk_info[i].name != NULL &&
400 strcmp(chunk_name, chunk_info[i].name) != 0)
403 if (chunk_info[i].name == NULL)
405 Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
406 chunk_name, filename);
407 ReadUnusedBytesFromFile(file, chunk_size);
409 else if (chunk_info[i].size != -1 &&
410 chunk_info[i].size != chunk_size)
412 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
413 chunk_size, chunk_name, filename);
414 ReadUnusedBytesFromFile(file, chunk_size);
418 /* call function to load this level chunk */
419 int chunk_size_expected =
420 (chunk_info[i].loader)(file, chunk_size, &level);
422 /* the size of some chunks cannot be checked before reading other
423 chunks first (like "HEAD" and "BODY") that contain some header
424 information, so check them here */
425 if (chunk_size_expected != chunk_size)
427 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
428 chunk_size, chunk_name, filename);
436 if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
437 IS_LEVELCLASS_USER(leveldir_current))
439 /* For user contributed and private levels, use the version of
440 the game engine the levels were created for.
441 Since 2.0.1, the game engine version is now directly stored
442 in the level file (chunk "VERS"), so there is no need anymore
443 to set the game version from the file version (except for old,
444 pre-2.0 levels, where the game version is still taken from the
445 file format version used to store the level -- see above). */
447 /* do some special adjustments to support older level versions */
448 if (level.file_version == FILE_VERSION_1_0)
450 Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
451 Error(ERR_WARN, "using high speed movement for player");
453 /* player was faster than monsters in (pre-)1.0 levels */
454 level.double_speed = TRUE;
457 /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
458 if (level.game_version == VERSION_IDENT(2,0,1))
459 level.em_slippery_gems = TRUE;
463 /* Always use the latest version of the game engine for all but
464 user contributed and private levels; this allows for actual
465 corrections in the game engine to take effect for existing,
466 converted levels (from "classic" or other existing games) to
467 make the game emulation more accurate, while (hopefully) not
468 breaking existing levels created from other players. */
470 level.game_version = GAME_VERSION_ACTUAL;
472 /* Set special EM style gems behaviour: EM style gems slip down from
473 normal, steel and growing wall. As this is a more fundamental change,
474 it seems better to set the default behaviour to "off" (as it is more
475 natural) and make it configurable in the level editor (as a property
476 of gem style elements). Already existing converted levels (neither
477 private nor contributed levels) are changed to the new behaviour. */
479 if (level.file_version < FILE_VERSION_2_0)
480 level.em_slippery_gems = TRUE;
483 /* determine border element for this level */
487 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
489 putFileVersion(file, level->file_version);
490 putFileVersion(file, level->game_version);
493 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
497 fputc(level->fieldx, file);
498 fputc(level->fieldy, file);
500 putFile16BitBE(file, level->time);
501 putFile16BitBE(file, level->gems_needed);
503 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
504 fputc(level->name[i], file);
506 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
507 fputc(level->score[i], file);
509 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
512 fputc((level->encoding_16bit_yamyam ? EL_EMPTY :
513 level->yam_content[i][x][y]),
515 fputc(level->amoeba_speed, file);
516 fputc(level->time_magic_wall, file);
517 fputc(level->time_wheel, file);
518 fputc((level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content),
520 fputc((level->double_speed ? 1 : 0), file);
521 fputc((level->gravity ? 1 : 0), file);
522 fputc((level->encoding_16bit_field ? 1 : 0), file);
523 fputc((level->em_slippery_gems ? 1 : 0), file);
525 WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
528 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
532 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
533 fputc(level->author[i], file);
537 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
541 fputc(EL_YAMYAM, file);
542 fputc(level->num_yam_contents, file);
546 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
549 if (level->encoding_16bit_field)
550 putFile16BitBE(file, level->yam_content[i][x][y]);
552 fputc(level->yam_content[i][x][y], file);
556 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
560 for(y=0; y<level->fieldy; y++)
561 for(x=0; x<level->fieldx; x++)
562 if (level->encoding_16bit_field)
563 putFile16BitBE(file, Ur[x][y]);
565 fputc(Ur[x][y], file);
568 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
571 int num_contents, content_xsize, content_ysize;
572 int content_array[MAX_ELEMENT_CONTENTS][3][3];
574 if (element == EL_YAMYAM)
576 num_contents = level->num_yam_contents;
580 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
583 content_array[i][x][y] = level->yam_content[i][x][y];
585 else if (element == EL_BD_AMOEBA)
591 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
594 content_array[i][x][y] = EL_EMPTY;
595 content_array[0][0][0] = level->amoeba_content;
599 /* chunk header already written -- write empty chunk data */
600 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
602 Error(ERR_WARN, "cannot save content for element '%d'", element);
606 putFile16BitBE(file, element);
607 fputc(num_contents, file);
608 fputc(content_xsize, file);
609 fputc(content_ysize, file);
611 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
613 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
616 putFile16BitBE(file, content_array[i][x][y]);
619 void SaveLevel(int level_nr)
622 char *filename = getLevelFilename(level_nr);
626 if (!(file = fopen(filename, MODE_WRITE)))
628 Error(ERR_WARN, "cannot save level file '%s'", filename);
632 level.file_version = FILE_VERSION_ACTUAL;
633 level.game_version = GAME_VERSION_ACTUAL;
635 /* check level field for 16-bit elements */
636 level.encoding_16bit_field = FALSE;
637 for(y=0; y<level.fieldy; y++)
638 for(x=0; x<level.fieldx; x++)
640 level.encoding_16bit_field = TRUE;
642 /* check yamyam content for 16-bit elements */
643 level.encoding_16bit_yamyam = FALSE;
644 for(i=0; i<level.num_yam_contents; i++)
647 if (level.yam_content[i][x][y] > 255)
648 level.encoding_16bit_yamyam = TRUE;
650 /* check amoeba content for 16-bit elements */
651 level.encoding_16bit_amoeba = FALSE;
652 if (level.amoeba_content > 255)
653 level.encoding_16bit_amoeba = TRUE;
656 level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
658 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
659 putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
661 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
662 SaveLevel_VERS(file, &level);
664 putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
665 SaveLevel_HEAD(file, &level);
667 putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
668 SaveLevel_AUTH(file, &level);
670 putFileChunkBE(file, "BODY", body_chunk_size);
671 SaveLevel_BODY(file, &level);
673 if (level.encoding_16bit_yamyam ||
674 level.num_yam_contents != STD_ELEMENT_CONTENTS)
676 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
677 SaveLevel_CNT2(file, &level, EL_YAMYAM);
680 if (level.encoding_16bit_amoeba)
682 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
683 SaveLevel_CNT2(file, &level, EL_BD_AMOEBA);
688 SetFilePermissions(filename, PERMS_PRIVATE);
692 /* ========================================================================= */
693 /* tape file functions */
694 /* ========================================================================= */
696 static void setTapeInfoToDefaults()
700 /* always start with reliable default values (empty tape) */
703 /* default values (also for pre-1.2 tapes) with only the first player */
704 tape.player_participates[0] = TRUE;
705 for(i=1; i<MAX_PLAYERS; i++)
706 tape.player_participates[i] = FALSE;
708 /* at least one (default: the first) player participates in every tape */
709 tape.num_participating_players = 1;
711 tape.level_nr = level_nr;
713 tape.changed = FALSE;
715 tape.recording = FALSE;
716 tape.playing = FALSE;
717 tape.pausing = FALSE;
720 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
722 tape->file_version = getFileVersion(file);
723 tape->game_version = getFileVersion(file);
728 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
732 tape->random_seed = getFile32BitBE(file);
733 tape->date = getFile32BitBE(file);
734 tape->length = getFile32BitBE(file);
736 /* read header fields that are new since version 1.2 */
737 if (tape->file_version >= FILE_VERSION_1_2)
739 byte store_participating_players = fgetc(file);
742 /* since version 1.2, tapes store which players participate in the tape */
743 tape->num_participating_players = 0;
744 for(i=0; i<MAX_PLAYERS; i++)
746 tape->player_participates[i] = FALSE;
748 if (store_participating_players & (1 << i))
750 tape->player_participates[i] = TRUE;
751 tape->num_participating_players++;
755 ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
757 engine_version = getFileVersion(file);
758 if (engine_version > 0)
759 tape->engine_version = engine_version;
765 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
768 int chunk_size_expected =
769 (tape->num_participating_players + 1) * tape->length;
771 if (chunk_size_expected != chunk_size)
773 ReadUnusedBytesFromFile(file, chunk_size);
774 return chunk_size_expected;
777 for(i=0; i<tape->length; i++)
779 if (i >= MAX_TAPELEN)
782 for(j=0; j<MAX_PLAYERS; j++)
784 tape->pos[i].action[j] = MV_NO_MOVING;
786 if (tape->player_participates[j])
787 tape->pos[i].action[j] = fgetc(file);
790 tape->pos[i].delay = fgetc(file);
792 if (tape->file_version == FILE_VERSION_1_0)
794 /* eliminate possible diagonal moves in old tapes */
795 /* this is only for backward compatibility */
797 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
798 byte action = tape->pos[i].action[0];
799 int k, num_moves = 0;
803 if (action & joy_dir[k])
805 tape->pos[i + num_moves].action[0] = joy_dir[k];
807 tape->pos[i + num_moves].delay = 0;
816 tape->length += num_moves;
819 else if (tape->file_version < FILE_VERSION_2_0)
821 /* convert pre-2.0 tapes to new tape format */
823 if (tape->pos[i].delay > 1)
826 tape->pos[i + 1] = tape->pos[i];
827 tape->pos[i + 1].delay = 1;
830 for(j=0; j<MAX_PLAYERS; j++)
831 tape->pos[i].action[j] = MV_NO_MOVING;
832 tape->pos[i].delay--;
843 if (i != tape->length)
844 chunk_size = (tape->num_participating_players + 1) * i;
849 void LoadTapeFromFilename(char *filename)
851 char cookie[MAX_LINE_LEN];
852 char chunk_name[CHUNK_ID_LEN + 1];
856 /* always start with reliable default values */
857 setTapeInfoToDefaults();
859 if (!(file = fopen(filename, MODE_READ)))
862 getFileChunkBE(file, chunk_name, NULL);
863 if (strcmp(chunk_name, "RND1") == 0)
865 getFile32BitBE(file); /* not used */
867 getFileChunkBE(file, chunk_name, NULL);
868 if (strcmp(chunk_name, "TAPE") != 0)
870 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
875 else /* check for pre-2.0 file format with cookie string */
877 strcpy(cookie, chunk_name);
878 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
879 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
880 cookie[strlen(cookie) - 1] = '\0';
882 if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
884 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
889 if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
891 Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
896 /* pre-2.0 tape files have no game version, so use file version here */
897 tape.game_version = tape.file_version;
900 if (tape.file_version < FILE_VERSION_1_2)
902 /* tape files from versions before 1.2.0 without chunk structure */
903 LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
904 LoadTape_BODY(file, 2 * tape.length, &tape);
912 int (*loader)(FILE *, int, struct TapeInfo *);
916 { "VERS", FILE_VERS_CHUNK_SIZE, LoadTape_VERS },
917 { "HEAD", TAPE_HEADER_SIZE, LoadTape_HEAD },
918 { "BODY", -1, LoadTape_BODY },
922 while (getFileChunkBE(file, chunk_name, &chunk_size))
926 while (chunk_info[i].name != NULL &&
927 strcmp(chunk_name, chunk_info[i].name) != 0)
930 if (chunk_info[i].name == NULL)
932 Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
933 chunk_name, filename);
934 ReadUnusedBytesFromFile(file, chunk_size);
936 else if (chunk_info[i].size != -1 &&
937 chunk_info[i].size != chunk_size)
939 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
940 chunk_size, chunk_name, filename);
941 ReadUnusedBytesFromFile(file, chunk_size);
945 /* call function to load this tape chunk */
946 int chunk_size_expected =
947 (chunk_info[i].loader)(file, chunk_size, &tape);
949 /* the size of some chunks cannot be checked before reading other
950 chunks first (like "HEAD" and "BODY") that contain some header
951 information, so check them here */
952 if (chunk_size_expected != chunk_size)
954 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
955 chunk_size, chunk_name, filename);
963 tape.length_seconds = GetTapeLength();
966 void LoadTape(int level_nr)
968 char *filename = getTapeFilename(level_nr);
970 LoadTapeFromFilename(filename);
973 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
975 putFileVersion(file, tape->file_version);
976 putFileVersion(file, tape->game_version);
979 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
982 byte store_participating_players = 0;
984 /* set bits for participating players for compact storage */
985 for(i=0; i<MAX_PLAYERS; i++)
986 if (tape->player_participates[i])
987 store_participating_players |= (1 << i);
989 putFile32BitBE(file, tape->random_seed);
990 putFile32BitBE(file, tape->date);
991 putFile32BitBE(file, tape->length);
993 fputc(store_participating_players, file);
995 /* unused bytes not at the end here for 4-byte alignment of engine_version */
996 WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
998 putFileVersion(file, tape->engine_version);
1001 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
1005 for(i=0; i<tape->length; i++)
1007 for(j=0; j<MAX_PLAYERS; j++)
1008 if (tape->player_participates[j])
1009 fputc(tape->pos[i].action[j], file);
1011 fputc(tape->pos[i].delay, file);
1015 void SaveTape(int level_nr)
1018 char *filename = getTapeFilename(level_nr);
1020 boolean new_tape = TRUE;
1021 int num_participating_players = 0;
1022 int body_chunk_size;
1024 InitTapeDirectory(leveldir_current->filename);
1026 /* if a tape still exists, ask to overwrite it */
1027 if (access(filename, F_OK) == 0)
1030 if (!Request("Replace old tape ?", REQ_ASK))
1034 if (!(file = fopen(filename, MODE_WRITE)))
1036 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
1040 tape.file_version = FILE_VERSION_ACTUAL;
1041 tape.game_version = GAME_VERSION_ACTUAL;
1043 /* count number of participating players */
1044 for(i=0; i<MAX_PLAYERS; i++)
1045 if (tape.player_participates[i])
1046 num_participating_players++;
1048 body_chunk_size = (num_participating_players + 1) * tape.length;
1050 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1051 putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
1053 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1054 SaveTape_VERS(file, &tape);
1056 putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
1057 SaveTape_HEAD(file, &tape);
1059 putFileChunkBE(file, "BODY", body_chunk_size);
1060 SaveTape_BODY(file, &tape);
1064 SetFilePermissions(filename, PERMS_PRIVATE);
1066 tape.changed = FALSE;
1069 Request("tape saved !", REQ_CONFIRM);
1072 void DumpTape(struct TapeInfo *tape)
1076 if (TAPE_IS_EMPTY(*tape))
1078 Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
1082 printf_line('-', 79);
1083 printf("Tape of Level %d (file version %06d, game version %06d)\n",
1084 tape->level_nr, tape->file_version, tape->game_version);
1085 printf_line('-', 79);
1087 for(i=0; i<tape->length; i++)
1089 if (i >= MAX_TAPELEN)
1092 printf("%03d: ", i);
1094 for(j=0; j<MAX_PLAYERS; j++)
1096 if (tape->player_participates[j])
1098 int action = tape->pos[i].action[j];
1100 printf("%d:%02x ", j, action);
1101 printf("[%c%c%c%c|%c%c] - ",
1102 (action & JOY_LEFT ? '<' : ' '),
1103 (action & JOY_RIGHT ? '>' : ' '),
1104 (action & JOY_UP ? '^' : ' '),
1105 (action & JOY_DOWN ? 'v' : ' '),
1106 (action & JOY_BUTTON_1 ? '1' : ' '),
1107 (action & JOY_BUTTON_2 ? '2' : ' '));
1111 printf("(%03d)\n", tape->pos[i].delay);
1114 printf_line('-', 79);
1118 /* ========================================================================= */
1119 /* score file functions */
1120 /* ========================================================================= */
1122 void LoadScore(int level_nr)
1125 char *filename = getScoreFilename(level_nr);
1126 char cookie[MAX_LINE_LEN];
1127 char line[MAX_LINE_LEN];
1131 /* always start with reliable default values */
1132 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1134 strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
1135 highscore[i].Score = 0;
1138 if (!(file = fopen(filename, MODE_READ)))
1141 /* check file identifier */
1142 fgets(cookie, MAX_LINE_LEN, file);
1143 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1144 cookie[strlen(cookie) - 1] = '\0';
1146 if (!checkCookieString(cookie, SCORE_COOKIE))
1148 Error(ERR_WARN, "unknown format of score file '%s'", filename);
1153 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1155 fscanf(file, "%d", &highscore[i].Score);
1156 fgets(line, MAX_LINE_LEN, file);
1158 if (line[strlen(line) - 1] == '\n')
1159 line[strlen(line) - 1] = '\0';
1161 for (line_ptr = line; *line_ptr; line_ptr++)
1163 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
1165 strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
1166 highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
1175 void SaveScore(int level_nr)
1178 char *filename = getScoreFilename(level_nr);
1181 InitScoreDirectory(leveldir_current->filename);
1183 if (!(file = fopen(filename, MODE_WRITE)))
1185 Error(ERR_WARN, "cannot save score for level %d", level_nr);
1189 fprintf(file, "%s\n\n", SCORE_COOKIE);
1191 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1192 fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
1196 SetFilePermissions(filename, PERMS_PUBLIC);
1200 /* ========================================================================= */
1201 /* setup file functions */
1202 /* ========================================================================= */
1204 #define TOKEN_STR_PLAYER_PREFIX "player_"
1207 #define SETUP_TOKEN_PLAYER_NAME 0
1208 #define SETUP_TOKEN_SOUND 1
1209 #define SETUP_TOKEN_SOUND_LOOPS 2
1210 #define SETUP_TOKEN_SOUND_MUSIC 3
1211 #define SETUP_TOKEN_SOUND_SIMPLE 4
1212 #define SETUP_TOKEN_TOONS 5
1213 #define SETUP_TOKEN_SCROLL_DELAY 6
1214 #define SETUP_TOKEN_SOFT_SCROLLING 7
1215 #define SETUP_TOKEN_FADING 8
1216 #define SETUP_TOKEN_AUTORECORD 9
1217 #define SETUP_TOKEN_QUICK_DOORS 10
1218 #define SETUP_TOKEN_TEAM_MODE 11
1219 #define SETUP_TOKEN_HANDICAP 12
1220 #define SETUP_TOKEN_TIME_LIMIT 13
1221 #define SETUP_TOKEN_FULLSCREEN 14
1222 #define SETUP_TOKEN_ASK_ON_ESCAPE 15
1223 #define SETUP_TOKEN_GRAPHICS_SET 16
1224 #define SETUP_TOKEN_SOUNDS_SET 17
1225 #define SETUP_TOKEN_MUSIC_SET 18
1226 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 19
1227 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 20
1228 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 21
1230 #define NUM_GLOBAL_SETUP_TOKENS 22
1233 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH 0
1234 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE 1
1235 #define SETUP_TOKEN_EDITOR_EL_MORE 2
1236 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN 3
1237 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX 4
1238 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES 5
1239 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH 6
1240 #define SETUP_TOKEN_EDITOR_EL_CHARS 7
1241 #define SETUP_TOKEN_EDITOR_EL_CUSTOM 8
1243 #define NUM_EDITOR_SETUP_TOKENS 9
1245 /* shortcut setup */
1246 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0
1247 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME 1
1248 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE 2
1250 #define NUM_SHORTCUT_SETUP_TOKENS 3
1253 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK 0
1254 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME 1
1255 #define SETUP_TOKEN_PLAYER_JOY_XLEFT 2
1256 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE 3
1257 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT 4
1258 #define SETUP_TOKEN_PLAYER_JOY_YUPPER 5
1259 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE 6
1260 #define SETUP_TOKEN_PLAYER_JOY_YLOWER 7
1261 #define SETUP_TOKEN_PLAYER_JOY_SNAP 8
1262 #define SETUP_TOKEN_PLAYER_JOY_BOMB 9
1263 #define SETUP_TOKEN_PLAYER_KEY_LEFT 10
1264 #define SETUP_TOKEN_PLAYER_KEY_RIGHT 11
1265 #define SETUP_TOKEN_PLAYER_KEY_UP 12
1266 #define SETUP_TOKEN_PLAYER_KEY_DOWN 13
1267 #define SETUP_TOKEN_PLAYER_KEY_SNAP 14
1268 #define SETUP_TOKEN_PLAYER_KEY_BOMB 15
1270 #define NUM_PLAYER_SETUP_TOKENS 16
1272 static struct SetupInfo si;
1273 static struct SetupEditorInfo sei;
1274 static struct SetupShortcutInfo ssi;
1275 static struct SetupInputInfo sii;
1277 static struct TokenInfo global_setup_tokens[] =
1280 { TYPE_STRING, &si.player_name, "player_name" },
1281 { TYPE_SWITCH, &si.sound, "sound" },
1282 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
1283 { TYPE_SWITCH, &si.sound_music, "background_music" },
1284 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
1285 { TYPE_SWITCH, &si.toons, "toons" },
1286 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
1287 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
1288 { TYPE_SWITCH, &si.fading, "screen_fading" },
1289 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
1290 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
1291 { TYPE_SWITCH, &si.team_mode, "team_mode" },
1292 { TYPE_SWITCH, &si.handicap, "handicap" },
1293 { TYPE_SWITCH, &si.time_limit, "time_limit" },
1294 { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
1295 { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
1296 { TYPE_STRING, &si.graphics_set, "graphics_set" },
1297 { TYPE_STRING, &si.sounds_set, "sounds_set" },
1298 { TYPE_STRING, &si.music_set, "music_set" },
1299 { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
1300 { TYPE_SWITCH, &si.override_level_sounds, "override_level_sounds" },
1301 { TYPE_SWITCH, &si.override_level_music, "override_level_music" },
1304 static struct TokenInfo editor_setup_tokens[] =
1306 /* shortcut setup */
1307 { TYPE_SWITCH, &sei.el_boulderdash, "editor.el_boulderdash" },
1308 { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine" },
1309 { TYPE_SWITCH, &sei.el_more, "editor.el_more" },
1310 { TYPE_SWITCH, &sei.el_sokoban, "editor.el_sokoban" },
1311 { TYPE_SWITCH, &sei.el_supaplex, "editor.el_supaplex" },
1312 { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves" },
1313 { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash" },
1314 { TYPE_SWITCH, &sei.el_chars, "editor.el_chars" },
1315 { TYPE_SWITCH, &sei.el_custom, "editor.el_custom" },
1318 static struct TokenInfo shortcut_setup_tokens[] =
1320 /* shortcut setup */
1321 { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
1322 { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
1323 { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }
1326 static struct TokenInfo player_setup_tokens[] =
1329 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
1330 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
1331 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
1332 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
1333 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
1334 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
1335 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
1336 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
1337 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
1338 { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
1339 { TYPE_KEY_X11, &sii.key.left, ".key.move_left" },
1340 { TYPE_KEY_X11, &sii.key.right, ".key.move_right" },
1341 { TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
1342 { TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
1343 { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
1344 { TYPE_KEY_X11, &sii.key.bomb, ".key.place_bomb" }
1347 static void setSetupInfoToDefaults(struct SetupInfo *si)
1351 si->player_name = getStringCopy(getLoginName());
1354 si->sound_loops = TRUE;
1355 si->sound_music = TRUE;
1356 si->sound_simple = TRUE;
1358 si->double_buffering = TRUE;
1359 si->direct_draw = !si->double_buffering;
1360 si->scroll_delay = TRUE;
1361 si->soft_scrolling = TRUE;
1363 si->autorecord = TRUE;
1364 si->quick_doors = FALSE;
1365 si->team_mode = FALSE;
1366 si->handicap = TRUE;
1367 si->time_limit = TRUE;
1368 si->fullscreen = FALSE;
1369 si->ask_on_escape = TRUE;
1371 si->graphics_set = getStringCopy(GRAPHICS_SUBDIR);
1372 si->sounds_set = getStringCopy(SOUNDS_SUBDIR);
1373 si->music_set = getStringCopy(MUSIC_SUBDIR);
1374 si->override_level_graphics = FALSE;
1375 si->override_level_sounds = FALSE;
1376 si->override_level_music = FALSE;
1378 si->editor.el_boulderdash = TRUE;
1379 si->editor.el_emerald_mine = TRUE;
1380 si->editor.el_more = TRUE;
1381 si->editor.el_sokoban = TRUE;
1382 si->editor.el_supaplex = TRUE;
1383 si->editor.el_diamond_caves = TRUE;
1384 si->editor.el_dx_boulderdash = TRUE;
1385 si->editor.el_chars = TRUE;
1386 si->editor.el_custom = FALSE;
1388 si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
1389 si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
1390 si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
1392 for (i=0; i<MAX_PLAYERS; i++)
1394 si->input[i].use_joystick = FALSE;
1395 si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
1396 si->input[i].joy.xleft = JOYSTICK_XLEFT;
1397 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1398 si->input[i].joy.xright = JOYSTICK_XRIGHT;
1399 si->input[i].joy.yupper = JOYSTICK_YUPPER;
1400 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1401 si->input[i].joy.ylower = JOYSTICK_YLOWER;
1402 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
1403 si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
1404 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
1405 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
1406 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
1407 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
1408 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
1409 si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED);
1413 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
1417 if (!setup_file_list)
1422 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1423 setSetupInfo(global_setup_tokens, i,
1424 getTokenValue(setup_file_list, global_setup_tokens[i].text));
1429 for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
1430 setSetupInfo(editor_setup_tokens, i,
1431 getTokenValue(setup_file_list,editor_setup_tokens[i].text));
1434 /* shortcut setup */
1435 ssi = setup.shortcut;
1436 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1437 setSetupInfo(shortcut_setup_tokens, i,
1438 getTokenValue(setup_file_list,shortcut_setup_tokens[i].text));
1439 setup.shortcut = ssi;
1442 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1446 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1448 sii = setup.input[pnr];
1449 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1451 char full_token[100];
1453 sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
1454 setSetupInfo(player_setup_tokens, i,
1455 getTokenValue(setup_file_list, full_token));
1457 setup.input[pnr] = sii;
1463 char *filename = getSetupFilename();
1464 struct SetupFileList *setup_file_list = NULL;
1466 /* always start with reliable default values */
1467 setSetupInfoToDefaults(&setup);
1469 setup_file_list = loadSetupFileList(filename);
1471 if (setup_file_list)
1473 checkSetupFileListIdentifier(setup_file_list, getCookie("SETUP"));
1474 decodeSetupFileList(setup_file_list);
1476 setup.direct_draw = !setup.double_buffering;
1478 freeSetupFileList(setup_file_list);
1480 /* needed to work around problems with fixed length strings */
1481 if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN)
1482 setup.player_name[MAX_PLAYER_NAME_LEN] = '\0';
1483 else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN)
1485 char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
1487 strcpy(new_name, setup.player_name);
1488 free(setup.player_name);
1489 setup.player_name = new_name;
1493 Error(ERR_WARN, "using default setup values");
1498 char *filename = getSetupFilename();
1502 InitUserDataDirectory();
1504 if (!(file = fopen(filename, MODE_WRITE)))
1506 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1510 fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
1511 getCookie("SETUP")));
1512 fprintf(file, "\n");
1516 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1518 /* just to make things nicer :) */
1519 if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
1520 i == SETUP_TOKEN_GRAPHICS_SET)
1521 fprintf(file, "\n");
1523 fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
1528 fprintf(file, "\n");
1529 for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
1530 fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
1532 /* shortcut setup */
1533 ssi = setup.shortcut;
1534 fprintf(file, "\n");
1535 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1536 fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
1539 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1543 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1544 fprintf(file, "\n");
1546 sii = setup.input[pnr];
1547 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1548 fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
1553 SetFilePermissions(filename, PERMS_PRIVATE);