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 level.no_level_file = FALSE;
101 if (leveldir_current == NULL) /* only when dumping level */
104 /* try to determine better author name than 'anonymous' */
105 if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
107 strncpy(level.author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
108 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
112 switch (LEVELCLASS(leveldir_current))
114 case LEVELCLASS_TUTORIAL:
115 strcpy(level.author, PROGRAM_AUTHOR_STRING);
118 case LEVELCLASS_CONTRIBUTION:
119 strncpy(level.author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN);
120 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
123 case LEVELCLASS_USER:
124 strncpy(level.author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
125 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
129 /* keep default value */
135 static int checkLevelElement(int element)
137 if (element >= NUM_FILE_ELEMENTS)
139 Error(ERR_WARN, "invalid level element %d", element);
140 element = EL_CHAR_QUESTION;
142 else if (element == EL_PLAYER_OBSOLETE)
143 element = EL_PLAYER1;
144 else if (element == EL_KEY_OBSOLETE)
150 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
152 level->file_version = getFileVersion(file);
153 level->game_version = getFileVersion(file);
158 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
162 lev_fieldx = level->fieldx = fgetc(file);
163 lev_fieldy = level->fieldy = fgetc(file);
165 level->time = getFile16BitBE(file);
166 level->gems_needed = getFile16BitBE(file);
168 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
169 level->name[i] = fgetc(file);
170 level->name[MAX_LEVEL_NAME_LEN] = 0;
172 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
173 level->score[i] = fgetc(file);
175 level->num_yam_contents = STD_ELEMENT_CONTENTS;
176 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
179 level->yam_content[i][x][y] = checkLevelElement(fgetc(file));
181 level->amoeba_speed = fgetc(file);
182 level->time_magic_wall = fgetc(file);
183 level->time_wheel = fgetc(file);
184 level->amoeba_content = checkLevelElement(fgetc(file));
185 level->double_speed = (fgetc(file) == 1 ? TRUE : FALSE);
186 level->gravity = (fgetc(file) == 1 ? TRUE : FALSE);
187 level->encoding_16bit_field = (fgetc(file) == 1 ? TRUE : FALSE);
188 level->em_slippery_gems = (fgetc(file) == 1 ? TRUE : FALSE);
190 ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
195 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
199 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
200 level->author[i] = fgetc(file);
201 level->author[MAX_LEVEL_NAME_LEN] = 0;
206 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
210 int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
211 int chunk_size_expected = header_size + content_size;
213 /* Note: "chunk_size" was wrong before version 2.0 when elements are
214 stored with 16-bit encoding (and should be twice as big then).
215 Even worse, playfield data was stored 16-bit when only yamyam content
216 contained 16-bit elements and vice versa. */
218 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
219 chunk_size_expected += content_size;
221 if (chunk_size_expected != chunk_size)
223 ReadUnusedBytesFromFile(file, chunk_size);
224 return chunk_size_expected;
228 level->num_yam_contents = fgetc(file);
232 /* correct invalid number of content fields -- should never happen */
233 if (level->num_yam_contents < 1 ||
234 level->num_yam_contents > MAX_ELEMENT_CONTENTS)
235 level->num_yam_contents = STD_ELEMENT_CONTENTS;
237 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
240 level->yam_content[i][x][y] =
241 checkLevelElement(level->encoding_16bit_field ?
242 getFile16BitBE(file) : fgetc(file));
246 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
249 int chunk_size_expected = level->fieldx * level->fieldy;
251 /* Note: "chunk_size" was wrong before version 2.0 when elements are
252 stored with 16-bit encoding (and should be twice as big then).
253 Even worse, playfield data was stored 16-bit when only yamyam content
254 contained 16-bit elements and vice versa. */
256 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
257 chunk_size_expected *= 2;
259 if (chunk_size_expected != chunk_size)
261 ReadUnusedBytesFromFile(file, chunk_size);
262 return chunk_size_expected;
265 for(y=0; y<level->fieldy; y++)
266 for(x=0; x<level->fieldx; x++)
267 Feld[x][y] = Ur[x][y] =
268 checkLevelElement(level->encoding_16bit_field ?
269 getFile16BitBE(file) : fgetc(file));
273 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
277 int num_contents, content_xsize, content_ysize;
278 int content_array[MAX_ELEMENT_CONTENTS][3][3];
280 element = checkLevelElement(getFile16BitBE(file));
281 num_contents = fgetc(file);
282 content_xsize = fgetc(file);
283 content_ysize = fgetc(file);
284 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
286 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
289 content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
291 /* correct invalid number of content fields -- should never happen */
292 if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
293 num_contents = STD_ELEMENT_CONTENTS;
295 if (element == EL_YAMYAM)
297 level->num_yam_contents = num_contents;
299 for(i=0; i<num_contents; i++)
302 level->yam_content[i][x][y] = content_array[i][x][y];
304 else if (element == EL_BD_AMOEBA)
306 level->amoeba_content = content_array[0][0][0];
310 Error(ERR_WARN, "cannot load content for element '%d'", element);
316 void LoadLevelFromFilename(char *filename)
318 char cookie[MAX_LINE_LEN];
319 char chunk_name[CHUNK_ID_LEN + 1];
323 /* always start with reliable default values */
324 setLevelInfoToDefaults();
326 if (!(file = fopen(filename, MODE_READ)))
328 level.no_level_file = TRUE;
330 Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
334 getFileChunkBE(file, chunk_name, NULL);
335 if (strcmp(chunk_name, "RND1") == 0)
337 getFile32BitBE(file); /* not used */
339 getFileChunkBE(file, chunk_name, NULL);
340 if (strcmp(chunk_name, "CAVE") != 0)
342 Error(ERR_WARN, "unknown format of level file '%s'", filename);
347 else /* check for pre-2.0 file format with cookie string */
349 strcpy(cookie, chunk_name);
350 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
351 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
352 cookie[strlen(cookie) - 1] = '\0';
354 if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
356 Error(ERR_WARN, "unknown format of level file '%s'", filename);
361 if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
363 Error(ERR_WARN, "unsupported version of level file '%s'", filename);
368 /* pre-2.0 level files have no game version, so use file version here */
369 level.game_version = level.file_version;
372 if (level.file_version < FILE_VERSION_1_2)
374 /* level files from versions before 1.2.0 without chunk structure */
375 LoadLevel_HEAD(file, LEVEL_HEADER_SIZE, &level);
376 LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
384 int (*loader)(FILE *, int, struct LevelInfo *);
388 { "VERS", FILE_VERS_CHUNK_SIZE, LoadLevel_VERS },
389 { "HEAD", LEVEL_HEADER_SIZE, LoadLevel_HEAD },
390 { "AUTH", MAX_LEVEL_AUTHOR_LEN, LoadLevel_AUTH },
391 { "CONT", -1, LoadLevel_CONT },
392 { "BODY", -1, LoadLevel_BODY },
393 { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
397 while (getFileChunkBE(file, chunk_name, &chunk_size))
401 while (chunk_info[i].name != NULL &&
402 strcmp(chunk_name, chunk_info[i].name) != 0)
405 if (chunk_info[i].name == NULL)
407 Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
408 chunk_name, filename);
409 ReadUnusedBytesFromFile(file, chunk_size);
411 else if (chunk_info[i].size != -1 &&
412 chunk_info[i].size != chunk_size)
414 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
415 chunk_size, chunk_name, filename);
416 ReadUnusedBytesFromFile(file, chunk_size);
420 /* call function to load this level chunk */
421 int chunk_size_expected =
422 (chunk_info[i].loader)(file, chunk_size, &level);
424 /* the size of some chunks cannot be checked before reading other
425 chunks first (like "HEAD" and "BODY") that contain some header
426 information, so check them here */
427 if (chunk_size_expected != chunk_size)
429 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
430 chunk_size, chunk_name, filename);
438 if (leveldir_current == NULL) /* only when dumping level */
441 if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
442 IS_LEVELCLASS_USER(leveldir_current))
444 /* For user contributed and private levels, use the version of
445 the game engine the levels were created for.
446 Since 2.0.1, the game engine version is now directly stored
447 in the level file (chunk "VERS"), so there is no need anymore
448 to set the game version from the file version (except for old,
449 pre-2.0 levels, where the game version is still taken from the
450 file format version used to store the level -- see above). */
452 /* do some special adjustments to support older level versions */
453 if (level.file_version == FILE_VERSION_1_0)
455 Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
456 Error(ERR_WARN, "using high speed movement for player");
458 /* player was faster than monsters in (pre-)1.0 levels */
459 level.double_speed = TRUE;
462 /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
463 if (level.game_version == VERSION_IDENT(2,0,1))
464 level.em_slippery_gems = TRUE;
468 /* Always use the latest version of the game engine for all but
469 user contributed and private levels; this allows for actual
470 corrections in the game engine to take effect for existing,
471 converted levels (from "classic" or other existing games) to
472 make the game emulation more accurate, while (hopefully) not
473 breaking existing levels created from other players. */
475 level.game_version = GAME_VERSION_ACTUAL;
477 /* Set special EM style gems behaviour: EM style gems slip down from
478 normal, steel and growing wall. As this is a more fundamental change,
479 it seems better to set the default behaviour to "off" (as it is more
480 natural) and make it configurable in the level editor (as a property
481 of gem style elements). Already existing converted levels (neither
482 private nor contributed levels) are changed to the new behaviour. */
484 if (level.file_version < FILE_VERSION_2_0)
485 level.em_slippery_gems = TRUE;
488 /* determine border element for this level */
492 void LoadLevel(int level_nr)
494 char *filename = getLevelFilename(level_nr);
496 LoadLevelFromFilename(filename);
499 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
501 putFileVersion(file, level->file_version);
502 putFileVersion(file, level->game_version);
505 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
509 fputc(level->fieldx, file);
510 fputc(level->fieldy, file);
512 putFile16BitBE(file, level->time);
513 putFile16BitBE(file, level->gems_needed);
515 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
516 fputc(level->name[i], file);
518 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
519 fputc(level->score[i], file);
521 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
524 fputc((level->encoding_16bit_yamyam ? EL_EMPTY :
525 level->yam_content[i][x][y]),
527 fputc(level->amoeba_speed, file);
528 fputc(level->time_magic_wall, file);
529 fputc(level->time_wheel, file);
530 fputc((level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content),
532 fputc((level->double_speed ? 1 : 0), file);
533 fputc((level->gravity ? 1 : 0), file);
534 fputc((level->encoding_16bit_field ? 1 : 0), file);
535 fputc((level->em_slippery_gems ? 1 : 0), file);
537 WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
540 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
544 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
545 fputc(level->author[i], file);
549 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
553 fputc(EL_YAMYAM, file);
554 fputc(level->num_yam_contents, file);
558 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
561 if (level->encoding_16bit_field)
562 putFile16BitBE(file, level->yam_content[i][x][y]);
564 fputc(level->yam_content[i][x][y], file);
568 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
572 for(y=0; y<level->fieldy; y++)
573 for(x=0; x<level->fieldx; x++)
574 if (level->encoding_16bit_field)
575 putFile16BitBE(file, Ur[x][y]);
577 fputc(Ur[x][y], file);
580 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
583 int num_contents, content_xsize, content_ysize;
584 int content_array[MAX_ELEMENT_CONTENTS][3][3];
586 if (element == EL_YAMYAM)
588 num_contents = level->num_yam_contents;
592 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
595 content_array[i][x][y] = level->yam_content[i][x][y];
597 else if (element == EL_BD_AMOEBA)
603 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
606 content_array[i][x][y] = EL_EMPTY;
607 content_array[0][0][0] = level->amoeba_content;
611 /* chunk header already written -- write empty chunk data */
612 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
614 Error(ERR_WARN, "cannot save content for element '%d'", element);
618 putFile16BitBE(file, element);
619 fputc(num_contents, file);
620 fputc(content_xsize, file);
621 fputc(content_ysize, file);
623 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
625 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
628 putFile16BitBE(file, content_array[i][x][y]);
631 void SaveLevel(int level_nr)
634 char *filename = getLevelFilename(level_nr);
638 if (!(file = fopen(filename, MODE_WRITE)))
640 Error(ERR_WARN, "cannot save level file '%s'", filename);
644 level.file_version = FILE_VERSION_ACTUAL;
645 level.game_version = GAME_VERSION_ACTUAL;
647 /* check level field for 16-bit elements */
648 level.encoding_16bit_field = FALSE;
649 for(y=0; y<level.fieldy; y++)
650 for(x=0; x<level.fieldx; x++)
652 level.encoding_16bit_field = TRUE;
654 /* check yamyam content for 16-bit elements */
655 level.encoding_16bit_yamyam = FALSE;
656 for(i=0; i<level.num_yam_contents; i++)
659 if (level.yam_content[i][x][y] > 255)
660 level.encoding_16bit_yamyam = TRUE;
662 /* check amoeba content for 16-bit elements */
663 level.encoding_16bit_amoeba = FALSE;
664 if (level.amoeba_content > 255)
665 level.encoding_16bit_amoeba = TRUE;
668 level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
670 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
671 putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
673 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
674 SaveLevel_VERS(file, &level);
676 putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
677 SaveLevel_HEAD(file, &level);
679 putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
680 SaveLevel_AUTH(file, &level);
682 putFileChunkBE(file, "BODY", body_chunk_size);
683 SaveLevel_BODY(file, &level);
685 if (level.encoding_16bit_yamyam ||
686 level.num_yam_contents != STD_ELEMENT_CONTENTS)
688 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
689 SaveLevel_CNT2(file, &level, EL_YAMYAM);
692 if (level.encoding_16bit_amoeba)
694 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
695 SaveLevel_CNT2(file, &level, EL_BD_AMOEBA);
700 SetFilePermissions(filename, PERMS_PRIVATE);
703 void DumpLevel(struct LevelInfo *level)
705 printf_line("-", 79);
706 printf("Level xxx (file version %06d, game version %06d)\n",
707 level->file_version, level->game_version);
708 printf_line("-", 79);
710 printf("Level Author: '%s'\n", level->author);
711 printf("Level Title: '%s'\n", level->name);
713 printf("Playfield Size: %d x %d\n", level->fieldx, level->fieldy);
715 printf("Level Time: %d seconds\n", level->time);
716 printf("Gems needed: %d\n", level->gems_needed);
718 printf("Time for Magic Wall: %d seconds\n", level->time_magic_wall);
719 printf("Time for Wheel: %d seconds\n", level->time_wheel);
720 printf("Time for Light: %d seconds\n", level->time_light);
721 printf("Time for Timegate: %d seconds\n", level->time_timegate);
723 printf("Amoeba Speed: %d\n", level->amoeba_speed);
725 printf("Gravity: %s\n", (level->gravity ? "yes" : "no"));
726 printf("Double Speed Movement: %s\n", (level->double_speed ? "yes" : "no"));
727 printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
729 printf_line("-", 79);
733 /* ========================================================================= */
734 /* tape file functions */
735 /* ========================================================================= */
737 static void setTapeInfoToDefaults()
741 /* always start with reliable default values (empty tape) */
744 /* default values (also for pre-1.2 tapes) with only the first player */
745 tape.player_participates[0] = TRUE;
746 for(i=1; i<MAX_PLAYERS; i++)
747 tape.player_participates[i] = FALSE;
749 /* at least one (default: the first) player participates in every tape */
750 tape.num_participating_players = 1;
752 tape.level_nr = level_nr;
754 tape.changed = FALSE;
756 tape.recording = FALSE;
757 tape.playing = FALSE;
758 tape.pausing = FALSE;
761 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
763 tape->file_version = getFileVersion(file);
764 tape->game_version = getFileVersion(file);
769 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
773 tape->random_seed = getFile32BitBE(file);
774 tape->date = getFile32BitBE(file);
775 tape->length = getFile32BitBE(file);
777 /* read header fields that are new since version 1.2 */
778 if (tape->file_version >= FILE_VERSION_1_2)
780 byte store_participating_players = fgetc(file);
783 /* since version 1.2, tapes store which players participate in the tape */
784 tape->num_participating_players = 0;
785 for(i=0; i<MAX_PLAYERS; i++)
787 tape->player_participates[i] = FALSE;
789 if (store_participating_players & (1 << i))
791 tape->player_participates[i] = TRUE;
792 tape->num_participating_players++;
796 ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
798 engine_version = getFileVersion(file);
799 if (engine_version > 0)
800 tape->engine_version = engine_version;
806 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
809 int chunk_size_expected =
810 (tape->num_participating_players + 1) * tape->length;
812 if (chunk_size_expected != chunk_size)
814 ReadUnusedBytesFromFile(file, chunk_size);
815 return chunk_size_expected;
818 for(i=0; i<tape->length; i++)
820 if (i >= MAX_TAPELEN)
823 for(j=0; j<MAX_PLAYERS; j++)
825 tape->pos[i].action[j] = MV_NO_MOVING;
827 if (tape->player_participates[j])
828 tape->pos[i].action[j] = fgetc(file);
831 tape->pos[i].delay = fgetc(file);
833 if (tape->file_version == FILE_VERSION_1_0)
835 /* eliminate possible diagonal moves in old tapes */
836 /* this is only for backward compatibility */
838 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
839 byte action = tape->pos[i].action[0];
840 int k, num_moves = 0;
844 if (action & joy_dir[k])
846 tape->pos[i + num_moves].action[0] = joy_dir[k];
848 tape->pos[i + num_moves].delay = 0;
857 tape->length += num_moves;
860 else if (tape->file_version < FILE_VERSION_2_0)
862 /* convert pre-2.0 tapes to new tape format */
864 if (tape->pos[i].delay > 1)
867 tape->pos[i + 1] = tape->pos[i];
868 tape->pos[i + 1].delay = 1;
871 for(j=0; j<MAX_PLAYERS; j++)
872 tape->pos[i].action[j] = MV_NO_MOVING;
873 tape->pos[i].delay--;
884 if (i != tape->length)
885 chunk_size = (tape->num_participating_players + 1) * i;
890 void LoadTapeFromFilename(char *filename)
892 char cookie[MAX_LINE_LEN];
893 char chunk_name[CHUNK_ID_LEN + 1];
897 /* always start with reliable default values */
898 setTapeInfoToDefaults();
900 if (!(file = fopen(filename, MODE_READ)))
903 getFileChunkBE(file, chunk_name, NULL);
904 if (strcmp(chunk_name, "RND1") == 0)
906 getFile32BitBE(file); /* not used */
908 getFileChunkBE(file, chunk_name, NULL);
909 if (strcmp(chunk_name, "TAPE") != 0)
911 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
916 else /* check for pre-2.0 file format with cookie string */
918 strcpy(cookie, chunk_name);
919 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
920 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
921 cookie[strlen(cookie) - 1] = '\0';
923 if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
925 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
930 if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
932 Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
937 /* pre-2.0 tape files have no game version, so use file version here */
938 tape.game_version = tape.file_version;
941 if (tape.file_version < FILE_VERSION_1_2)
943 /* tape files from versions before 1.2.0 without chunk structure */
944 LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
945 LoadTape_BODY(file, 2 * tape.length, &tape);
953 int (*loader)(FILE *, int, struct TapeInfo *);
957 { "VERS", FILE_VERS_CHUNK_SIZE, LoadTape_VERS },
958 { "HEAD", TAPE_HEADER_SIZE, LoadTape_HEAD },
959 { "BODY", -1, LoadTape_BODY },
963 while (getFileChunkBE(file, chunk_name, &chunk_size))
967 while (chunk_info[i].name != NULL &&
968 strcmp(chunk_name, chunk_info[i].name) != 0)
971 if (chunk_info[i].name == NULL)
973 Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
974 chunk_name, filename);
975 ReadUnusedBytesFromFile(file, chunk_size);
977 else if (chunk_info[i].size != -1 &&
978 chunk_info[i].size != chunk_size)
980 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
981 chunk_size, chunk_name, filename);
982 ReadUnusedBytesFromFile(file, chunk_size);
986 /* call function to load this tape chunk */
987 int chunk_size_expected =
988 (chunk_info[i].loader)(file, chunk_size, &tape);
990 /* the size of some chunks cannot be checked before reading other
991 chunks first (like "HEAD" and "BODY") that contain some header
992 information, so check them here */
993 if (chunk_size_expected != chunk_size)
995 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
996 chunk_size, chunk_name, filename);
1004 tape.length_seconds = GetTapeLength();
1007 void LoadTape(int level_nr)
1009 char *filename = getTapeFilename(level_nr);
1011 LoadTapeFromFilename(filename);
1014 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
1016 putFileVersion(file, tape->file_version);
1017 putFileVersion(file, tape->game_version);
1020 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
1023 byte store_participating_players = 0;
1025 /* set bits for participating players for compact storage */
1026 for(i=0; i<MAX_PLAYERS; i++)
1027 if (tape->player_participates[i])
1028 store_participating_players |= (1 << i);
1030 putFile32BitBE(file, tape->random_seed);
1031 putFile32BitBE(file, tape->date);
1032 putFile32BitBE(file, tape->length);
1034 fputc(store_participating_players, file);
1036 /* unused bytes not at the end here for 4-byte alignment of engine_version */
1037 WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
1039 putFileVersion(file, tape->engine_version);
1042 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
1046 for(i=0; i<tape->length; i++)
1048 for(j=0; j<MAX_PLAYERS; j++)
1049 if (tape->player_participates[j])
1050 fputc(tape->pos[i].action[j], file);
1052 fputc(tape->pos[i].delay, file);
1056 void SaveTape(int level_nr)
1059 char *filename = getTapeFilename(level_nr);
1061 boolean new_tape = TRUE;
1062 int num_participating_players = 0;
1063 int body_chunk_size;
1065 InitTapeDirectory(leveldir_current->filename);
1067 /* if a tape still exists, ask to overwrite it */
1068 if (access(filename, F_OK) == 0)
1071 if (!Request("Replace old tape ?", REQ_ASK))
1075 if (!(file = fopen(filename, MODE_WRITE)))
1077 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
1081 tape.file_version = FILE_VERSION_ACTUAL;
1082 tape.game_version = GAME_VERSION_ACTUAL;
1084 /* count number of participating players */
1085 for(i=0; i<MAX_PLAYERS; i++)
1086 if (tape.player_participates[i])
1087 num_participating_players++;
1089 body_chunk_size = (num_participating_players + 1) * tape.length;
1091 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1092 putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
1094 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1095 SaveTape_VERS(file, &tape);
1097 putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
1098 SaveTape_HEAD(file, &tape);
1100 putFileChunkBE(file, "BODY", body_chunk_size);
1101 SaveTape_BODY(file, &tape);
1105 SetFilePermissions(filename, PERMS_PRIVATE);
1107 tape.changed = FALSE;
1110 Request("tape saved !", REQ_CONFIRM);
1113 void DumpTape(struct TapeInfo *tape)
1117 if (TAPE_IS_EMPTY(*tape))
1119 Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
1123 printf_line("-", 79);
1124 printf("Tape of Level %03d (file version %06d, game version %06d)\n",
1125 tape->level_nr, tape->file_version, tape->game_version);
1126 printf_line("-", 79);
1128 for(i=0; i<tape->length; i++)
1130 if (i >= MAX_TAPELEN)
1133 printf("%03d: ", i);
1135 for(j=0; j<MAX_PLAYERS; j++)
1137 if (tape->player_participates[j])
1139 int action = tape->pos[i].action[j];
1141 printf("%d:%02x ", j, action);
1142 printf("[%c%c%c%c|%c%c] - ",
1143 (action & JOY_LEFT ? '<' : ' '),
1144 (action & JOY_RIGHT ? '>' : ' '),
1145 (action & JOY_UP ? '^' : ' '),
1146 (action & JOY_DOWN ? 'v' : ' '),
1147 (action & JOY_BUTTON_1 ? '1' : ' '),
1148 (action & JOY_BUTTON_2 ? '2' : ' '));
1152 printf("(%03d)\n", tape->pos[i].delay);
1155 printf_line("-", 79);
1159 /* ========================================================================= */
1160 /* score file functions */
1161 /* ========================================================================= */
1163 void LoadScore(int level_nr)
1166 char *filename = getScoreFilename(level_nr);
1167 char cookie[MAX_LINE_LEN];
1168 char line[MAX_LINE_LEN];
1172 /* always start with reliable default values */
1173 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1175 strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
1176 highscore[i].Score = 0;
1179 if (!(file = fopen(filename, MODE_READ)))
1182 /* check file identifier */
1183 fgets(cookie, MAX_LINE_LEN, file);
1184 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1185 cookie[strlen(cookie) - 1] = '\0';
1187 if (!checkCookieString(cookie, SCORE_COOKIE))
1189 Error(ERR_WARN, "unknown format of score file '%s'", filename);
1194 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1196 fscanf(file, "%d", &highscore[i].Score);
1197 fgets(line, MAX_LINE_LEN, file);
1199 if (line[strlen(line) - 1] == '\n')
1200 line[strlen(line) - 1] = '\0';
1202 for (line_ptr = line; *line_ptr; line_ptr++)
1204 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
1206 strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
1207 highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
1216 void SaveScore(int level_nr)
1219 char *filename = getScoreFilename(level_nr);
1222 InitScoreDirectory(leveldir_current->filename);
1224 if (!(file = fopen(filename, MODE_WRITE)))
1226 Error(ERR_WARN, "cannot save score for level %d", level_nr);
1230 fprintf(file, "%s\n\n", SCORE_COOKIE);
1232 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1233 fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
1237 SetFilePermissions(filename, PERMS_PUBLIC);
1241 /* ========================================================================= */
1242 /* setup file functions */
1243 /* ========================================================================= */
1245 #define TOKEN_STR_PLAYER_PREFIX "player_"
1248 #define SETUP_TOKEN_PLAYER_NAME 0
1249 #define SETUP_TOKEN_SOUND 1
1250 #define SETUP_TOKEN_SOUND_LOOPS 2
1251 #define SETUP_TOKEN_SOUND_MUSIC 3
1252 #define SETUP_TOKEN_SOUND_SIMPLE 4
1253 #define SETUP_TOKEN_TOONS 5
1254 #define SETUP_TOKEN_SCROLL_DELAY 6
1255 #define SETUP_TOKEN_SOFT_SCROLLING 7
1256 #define SETUP_TOKEN_FADING 8
1257 #define SETUP_TOKEN_AUTORECORD 9
1258 #define SETUP_TOKEN_QUICK_DOORS 10
1259 #define SETUP_TOKEN_TEAM_MODE 11
1260 #define SETUP_TOKEN_HANDICAP 12
1261 #define SETUP_TOKEN_TIME_LIMIT 13
1262 #define SETUP_TOKEN_FULLSCREEN 14
1263 #define SETUP_TOKEN_ASK_ON_ESCAPE 15
1264 #define SETUP_TOKEN_GRAPHICS_SET 16
1265 #define SETUP_TOKEN_SOUNDS_SET 17
1266 #define SETUP_TOKEN_MUSIC_SET 18
1267 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 19
1268 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 20
1269 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 21
1271 #define NUM_GLOBAL_SETUP_TOKENS 22
1274 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH 0
1275 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE 1
1276 #define SETUP_TOKEN_EDITOR_EL_MORE 2
1277 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN 3
1278 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX 4
1279 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES 5
1280 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH 6
1281 #define SETUP_TOKEN_EDITOR_EL_CHARS 7
1282 #define SETUP_TOKEN_EDITOR_EL_CUSTOM 8
1284 #define NUM_EDITOR_SETUP_TOKENS 9
1286 /* shortcut setup */
1287 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0
1288 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME 1
1289 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE 2
1291 #define NUM_SHORTCUT_SETUP_TOKENS 3
1294 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK 0
1295 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME 1
1296 #define SETUP_TOKEN_PLAYER_JOY_XLEFT 2
1297 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE 3
1298 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT 4
1299 #define SETUP_TOKEN_PLAYER_JOY_YUPPER 5
1300 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE 6
1301 #define SETUP_TOKEN_PLAYER_JOY_YLOWER 7
1302 #define SETUP_TOKEN_PLAYER_JOY_SNAP 8
1303 #define SETUP_TOKEN_PLAYER_JOY_BOMB 9
1304 #define SETUP_TOKEN_PLAYER_KEY_LEFT 10
1305 #define SETUP_TOKEN_PLAYER_KEY_RIGHT 11
1306 #define SETUP_TOKEN_PLAYER_KEY_UP 12
1307 #define SETUP_TOKEN_PLAYER_KEY_DOWN 13
1308 #define SETUP_TOKEN_PLAYER_KEY_SNAP 14
1309 #define SETUP_TOKEN_PLAYER_KEY_BOMB 15
1311 #define NUM_PLAYER_SETUP_TOKENS 16
1313 static struct SetupInfo si;
1314 static struct SetupEditorInfo sei;
1315 static struct SetupShortcutInfo ssi;
1316 static struct SetupInputInfo sii;
1318 static struct TokenInfo global_setup_tokens[] =
1321 { TYPE_STRING, &si.player_name, "player_name" },
1322 { TYPE_SWITCH, &si.sound, "sound" },
1323 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
1324 { TYPE_SWITCH, &si.sound_music, "background_music" },
1325 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
1326 { TYPE_SWITCH, &si.toons, "toons" },
1327 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
1328 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
1329 { TYPE_SWITCH, &si.fading, "screen_fading" },
1330 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
1331 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
1332 { TYPE_SWITCH, &si.team_mode, "team_mode" },
1333 { TYPE_SWITCH, &si.handicap, "handicap" },
1334 { TYPE_SWITCH, &si.time_limit, "time_limit" },
1335 { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
1336 { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
1337 { TYPE_STRING, &si.graphics_set, "graphics_set" },
1338 { TYPE_STRING, &si.sounds_set, "sounds_set" },
1339 { TYPE_STRING, &si.music_set, "music_set" },
1340 { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
1341 { TYPE_SWITCH, &si.override_level_sounds, "override_level_sounds" },
1342 { TYPE_SWITCH, &si.override_level_music, "override_level_music" },
1345 static struct TokenInfo editor_setup_tokens[] =
1347 /* shortcut setup */
1348 { TYPE_SWITCH, &sei.el_boulderdash, "editor.el_boulderdash" },
1349 { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine" },
1350 { TYPE_SWITCH, &sei.el_more, "editor.el_more" },
1351 { TYPE_SWITCH, &sei.el_sokoban, "editor.el_sokoban" },
1352 { TYPE_SWITCH, &sei.el_supaplex, "editor.el_supaplex" },
1353 { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves" },
1354 { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash" },
1355 { TYPE_SWITCH, &sei.el_chars, "editor.el_chars" },
1356 { TYPE_SWITCH, &sei.el_custom, "editor.el_custom" },
1359 static struct TokenInfo shortcut_setup_tokens[] =
1361 /* shortcut setup */
1362 { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
1363 { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
1364 { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }
1367 static struct TokenInfo player_setup_tokens[] =
1370 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
1371 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
1372 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
1373 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
1374 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
1375 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
1376 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
1377 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
1378 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
1379 { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
1380 { TYPE_KEY_X11, &sii.key.left, ".key.move_left" },
1381 { TYPE_KEY_X11, &sii.key.right, ".key.move_right" },
1382 { TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
1383 { TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
1384 { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
1385 { TYPE_KEY_X11, &sii.key.bomb, ".key.place_bomb" }
1388 static void setSetupInfoToDefaults(struct SetupInfo *si)
1392 si->player_name = getStringCopy(getLoginName());
1395 si->sound_loops = TRUE;
1396 si->sound_music = TRUE;
1397 si->sound_simple = TRUE;
1399 si->double_buffering = TRUE;
1400 si->direct_draw = !si->double_buffering;
1401 si->scroll_delay = TRUE;
1402 si->soft_scrolling = TRUE;
1404 si->autorecord = TRUE;
1405 si->quick_doors = FALSE;
1406 si->team_mode = FALSE;
1407 si->handicap = TRUE;
1408 si->time_limit = TRUE;
1409 si->fullscreen = FALSE;
1410 si->ask_on_escape = TRUE;
1412 si->graphics_set = getStringCopy(GRAPHICS_SUBDIR);
1413 si->sounds_set = getStringCopy(SOUNDS_SUBDIR);
1414 si->music_set = getStringCopy(MUSIC_SUBDIR);
1415 si->override_level_graphics = FALSE;
1416 si->override_level_sounds = FALSE;
1417 si->override_level_music = FALSE;
1419 si->editor.el_boulderdash = TRUE;
1420 si->editor.el_emerald_mine = TRUE;
1421 si->editor.el_more = TRUE;
1422 si->editor.el_sokoban = TRUE;
1423 si->editor.el_supaplex = TRUE;
1424 si->editor.el_diamond_caves = TRUE;
1425 si->editor.el_dx_boulderdash = TRUE;
1426 si->editor.el_chars = TRUE;
1427 si->editor.el_custom = FALSE;
1429 si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
1430 si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
1431 si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
1433 for (i=0; i<MAX_PLAYERS; i++)
1435 si->input[i].use_joystick = FALSE;
1436 si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
1437 si->input[i].joy.xleft = JOYSTICK_XLEFT;
1438 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1439 si->input[i].joy.xright = JOYSTICK_XRIGHT;
1440 si->input[i].joy.yupper = JOYSTICK_YUPPER;
1441 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1442 si->input[i].joy.ylower = JOYSTICK_YLOWER;
1443 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
1444 si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
1445 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
1446 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
1447 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
1448 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
1449 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
1450 si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED);
1454 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
1458 if (!setup_file_list)
1463 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1464 setSetupInfo(global_setup_tokens, i,
1465 getTokenValue(setup_file_list, global_setup_tokens[i].text));
1470 for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
1471 setSetupInfo(editor_setup_tokens, i,
1472 getTokenValue(setup_file_list,editor_setup_tokens[i].text));
1475 /* shortcut setup */
1476 ssi = setup.shortcut;
1477 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1478 setSetupInfo(shortcut_setup_tokens, i,
1479 getTokenValue(setup_file_list,shortcut_setup_tokens[i].text));
1480 setup.shortcut = ssi;
1483 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1487 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1489 sii = setup.input[pnr];
1490 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1492 char full_token[100];
1494 sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
1495 setSetupInfo(player_setup_tokens, i,
1496 getTokenValue(setup_file_list, full_token));
1498 setup.input[pnr] = sii;
1504 char *filename = getSetupFilename();
1505 struct SetupFileList *setup_file_list = NULL;
1507 /* always start with reliable default values */
1508 setSetupInfoToDefaults(&setup);
1510 setup_file_list = loadSetupFileList(filename);
1512 if (setup_file_list)
1514 checkSetupFileListIdentifier(setup_file_list, getCookie("SETUP"));
1515 decodeSetupFileList(setup_file_list);
1517 setup.direct_draw = !setup.double_buffering;
1519 freeSetupFileList(setup_file_list);
1521 /* needed to work around problems with fixed length strings */
1522 if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN)
1523 setup.player_name[MAX_PLAYER_NAME_LEN] = '\0';
1524 else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN)
1526 char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
1528 strcpy(new_name, setup.player_name);
1529 free(setup.player_name);
1530 setup.player_name = new_name;
1534 Error(ERR_WARN, "using default setup values");
1539 char *filename = getSetupFilename();
1543 InitUserDataDirectory();
1545 if (!(file = fopen(filename, MODE_WRITE)))
1547 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1551 fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
1552 getCookie("SETUP")));
1553 fprintf(file, "\n");
1557 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1559 /* just to make things nicer :) */
1560 if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
1561 i == SETUP_TOKEN_GRAPHICS_SET)
1562 fprintf(file, "\n");
1564 fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
1569 fprintf(file, "\n");
1570 for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
1571 fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
1573 /* shortcut setup */
1574 ssi = setup.shortcut;
1575 fprintf(file, "\n");
1576 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1577 fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
1580 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1584 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1585 fprintf(file, "\n");
1587 sii = setup.input[pnr];
1588 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1589 fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
1594 SetFilePermissions(filename, PERMS_PRIVATE);