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_PLAYER;
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 */
130 static int checkLevelElement(int element)
132 if (element >= EL_FIRST_RUNTIME)
134 Error(ERR_WARN, "invalid level element %d", element);
135 element = EL_CHAR_QUESTION;
141 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
143 level->file_version = getFileVersion(file);
144 level->game_version = getFileVersion(file);
149 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
153 lev_fieldx = level->fieldx = fgetc(file);
154 lev_fieldy = level->fieldy = fgetc(file);
156 level->time = getFile16BitBE(file);
157 level->gems_needed = getFile16BitBE(file);
159 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
160 level->name[i] = fgetc(file);
161 level->name[MAX_LEVEL_NAME_LEN] = 0;
163 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
164 level->score[i] = fgetc(file);
166 level->num_yam_contents = STD_ELEMENT_CONTENTS;
167 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
170 level->yam_content[i][x][y] = checkLevelElement(fgetc(file));
172 level->amoeba_speed = fgetc(file);
173 level->time_magic_wall = fgetc(file);
174 level->time_wheel = fgetc(file);
175 level->amoeba_content = checkLevelElement(fgetc(file));
176 level->double_speed = (fgetc(file) == 1 ? TRUE : FALSE);
177 level->gravity = (fgetc(file) == 1 ? TRUE : FALSE);
178 level->encoding_16bit_field = (fgetc(file) == 1 ? TRUE : FALSE);
179 level->em_slippery_gems = (fgetc(file) == 1 ? TRUE : FALSE);
181 ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
186 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
190 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
191 level->author[i] = fgetc(file);
192 level->author[MAX_LEVEL_NAME_LEN] = 0;
197 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
201 int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
202 int chunk_size_expected = header_size + content_size;
204 /* Note: "chunk_size" was wrong before version 2.0 when elements are
205 stored with 16-bit encoding (and should be twice as big then).
206 Even worse, playfield data was stored 16-bit when only yamyam content
207 contained 16-bit elements and vice versa. */
209 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
210 chunk_size_expected += content_size;
212 if (chunk_size_expected != chunk_size)
214 ReadUnusedBytesFromFile(file, chunk_size);
215 return chunk_size_expected;
219 level->num_yam_contents = fgetc(file);
223 /* correct invalid number of content fields -- should never happen */
224 if (level->num_yam_contents < 1 ||
225 level->num_yam_contents > MAX_ELEMENT_CONTENTS)
226 level->num_yam_contents = STD_ELEMENT_CONTENTS;
228 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
231 level->yam_content[i][x][y] =
232 checkLevelElement(level->encoding_16bit_field ?
233 getFile16BitBE(file) : fgetc(file));
237 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
240 int chunk_size_expected = level->fieldx * level->fieldy;
242 /* Note: "chunk_size" was wrong before version 2.0 when elements are
243 stored with 16-bit encoding (and should be twice as big then).
244 Even worse, playfield data was stored 16-bit when only yamyam content
245 contained 16-bit elements and vice versa. */
247 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
248 chunk_size_expected *= 2;
250 if (chunk_size_expected != chunk_size)
252 ReadUnusedBytesFromFile(file, chunk_size);
253 return chunk_size_expected;
256 for(y=0; y<level->fieldy; y++)
257 for(x=0; x<level->fieldx; x++)
258 Feld[x][y] = Ur[x][y] =
259 checkLevelElement(level->encoding_16bit_field ?
260 getFile16BitBE(file) : fgetc(file));
264 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
268 int num_contents, content_xsize, content_ysize;
269 int content_array[MAX_ELEMENT_CONTENTS][3][3];
271 element = checkLevelElement(getFile16BitBE(file));
272 num_contents = fgetc(file);
273 content_xsize = fgetc(file);
274 content_ysize = fgetc(file);
275 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
277 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
280 content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
282 /* correct invalid number of content fields -- should never happen */
283 if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
284 num_contents = STD_ELEMENT_CONTENTS;
286 if (element == EL_YAMYAM)
288 level->num_yam_contents = num_contents;
290 for(i=0; i<num_contents; i++)
293 level->yam_content[i][x][y] = content_array[i][x][y];
295 else if (element == EL_BD_AMOEBA)
297 level->amoeba_content = content_array[0][0][0];
301 Error(ERR_WARN, "cannot load content for element '%d'", element);
307 void LoadLevel(int level_nr)
309 char *filename = getLevelFilename(level_nr);
310 char cookie[MAX_LINE_LEN];
311 char chunk_name[CHUNK_ID_LEN + 1];
315 /* always start with reliable default values */
316 setLevelInfoToDefaults();
318 if (!(file = fopen(filename, MODE_READ)))
320 Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
324 getFileChunkBE(file, chunk_name, NULL);
325 if (strcmp(chunk_name, "RND1") == 0)
327 getFile32BitBE(file); /* not used */
329 getFileChunkBE(file, chunk_name, NULL);
330 if (strcmp(chunk_name, "CAVE") != 0)
332 Error(ERR_WARN, "unknown format of level file '%s'", filename);
337 else /* check for pre-2.0 file format with cookie string */
339 strcpy(cookie, chunk_name);
340 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
341 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
342 cookie[strlen(cookie) - 1] = '\0';
344 if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
346 Error(ERR_WARN, "unknown format of level file '%s'", filename);
351 if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
353 Error(ERR_WARN, "unsupported version of level file '%s'", filename);
358 /* pre-2.0 level files have no game version, so use file version here */
359 level.game_version = level.file_version;
362 if (level.file_version < FILE_VERSION_1_2)
364 /* level files from versions before 1.2.0 without chunk structure */
365 LoadLevel_HEAD(file, LEVEL_HEADER_SIZE, &level);
366 LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
374 int (*loader)(FILE *, int, struct LevelInfo *);
378 { "VERS", FILE_VERS_CHUNK_SIZE, LoadLevel_VERS },
379 { "HEAD", LEVEL_HEADER_SIZE, LoadLevel_HEAD },
380 { "AUTH", MAX_LEVEL_AUTHOR_LEN, LoadLevel_AUTH },
381 { "CONT", -1, LoadLevel_CONT },
382 { "BODY", -1, LoadLevel_BODY },
383 { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
387 while (getFileChunkBE(file, chunk_name, &chunk_size))
391 while (chunk_info[i].name != NULL &&
392 strcmp(chunk_name, chunk_info[i].name) != 0)
395 if (chunk_info[i].name == NULL)
397 Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
398 chunk_name, filename);
399 ReadUnusedBytesFromFile(file, chunk_size);
401 else if (chunk_info[i].size != -1 &&
402 chunk_info[i].size != chunk_size)
404 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
405 chunk_size, chunk_name, filename);
406 ReadUnusedBytesFromFile(file, chunk_size);
410 /* call function to load this level chunk */
411 int chunk_size_expected =
412 (chunk_info[i].loader)(file, chunk_size, &level);
414 /* the size of some chunks cannot be checked before reading other
415 chunks first (like "HEAD" and "BODY") that contain some header
416 information, so check them here */
417 if (chunk_size_expected != chunk_size)
419 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
420 chunk_size, chunk_name, filename);
428 if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
429 IS_LEVELCLASS_USER(leveldir_current))
431 /* For user contributed and private levels, use the version of
432 the game engine the levels were created for.
433 Since 2.0.1, the game engine version is now directly stored
434 in the level file (chunk "VERS"), so there is no need anymore
435 to set the game version from the file version (except for old,
436 pre-2.0 levels, where the game version is still taken from the
437 file format version used to store the level -- see above). */
439 /* do some special adjustments to support older level versions */
440 if (level.file_version == FILE_VERSION_1_0)
442 Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
443 Error(ERR_WARN, "using high speed movement for player");
445 /* player was faster than monsters in (pre-)1.0 levels */
446 level.double_speed = TRUE;
449 /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
450 if (level.game_version == VERSION_IDENT(2,0,1))
451 level.em_slippery_gems = TRUE;
455 /* Always use the latest version of the game engine for all but
456 user contributed and private levels; this allows for actual
457 corrections in the game engine to take effect for existing,
458 converted levels (from "classic" or other existing games) to
459 make the game emulation more accurate, while (hopefully) not
460 breaking existing levels created from other players. */
462 level.game_version = GAME_VERSION_ACTUAL;
464 /* Set special EM style gems behaviour: EM style gems slip down from
465 normal, steel and growing wall. As this is a more fundamental change,
466 it seems better to set the default behaviour to "off" (as it is more
467 natural) and make it configurable in the level editor (as a property
468 of gem style elements). Already existing converted levels (neither
469 private nor contributed levels) are changed to the new behaviour. */
471 if (level.file_version < FILE_VERSION_2_0)
472 level.em_slippery_gems = TRUE;
475 /* determine border element for this level */
479 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
481 putFileVersion(file, level->file_version);
482 putFileVersion(file, level->game_version);
485 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
489 fputc(level->fieldx, file);
490 fputc(level->fieldy, file);
492 putFile16BitBE(file, level->time);
493 putFile16BitBE(file, level->gems_needed);
495 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
496 fputc(level->name[i], file);
498 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
499 fputc(level->score[i], file);
501 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
504 fputc((level->encoding_16bit_yamyam ? EL_EMPTY :
505 level->yam_content[i][x][y]),
507 fputc(level->amoeba_speed, file);
508 fputc(level->time_magic_wall, file);
509 fputc(level->time_wheel, file);
510 fputc((level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content),
512 fputc((level->double_speed ? 1 : 0), file);
513 fputc((level->gravity ? 1 : 0), file);
514 fputc((level->encoding_16bit_field ? 1 : 0), file);
515 fputc((level->em_slippery_gems ? 1 : 0), file);
517 WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
520 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
524 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
525 fputc(level->author[i], file);
529 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
533 fputc(EL_YAMYAM, file);
534 fputc(level->num_yam_contents, file);
538 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
541 if (level->encoding_16bit_field)
542 putFile16BitBE(file, level->yam_content[i][x][y]);
544 fputc(level->yam_content[i][x][y], file);
548 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
552 for(y=0; y<level->fieldy; y++)
553 for(x=0; x<level->fieldx; x++)
554 if (level->encoding_16bit_field)
555 putFile16BitBE(file, Ur[x][y]);
557 fputc(Ur[x][y], file);
560 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
563 int num_contents, content_xsize, content_ysize;
564 int content_array[MAX_ELEMENT_CONTENTS][3][3];
566 if (element == EL_YAMYAM)
568 num_contents = level->num_yam_contents;
572 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
575 content_array[i][x][y] = level->yam_content[i][x][y];
577 else if (element == EL_BD_AMOEBA)
583 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
586 content_array[i][x][y] = EL_EMPTY;
587 content_array[0][0][0] = level->amoeba_content;
591 /* chunk header already written -- write empty chunk data */
592 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
594 Error(ERR_WARN, "cannot save content for element '%d'", element);
598 putFile16BitBE(file, element);
599 fputc(num_contents, file);
600 fputc(content_xsize, file);
601 fputc(content_ysize, file);
603 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
605 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
608 putFile16BitBE(file, content_array[i][x][y]);
611 void SaveLevel(int level_nr)
614 char *filename = getLevelFilename(level_nr);
618 if (!(file = fopen(filename, MODE_WRITE)))
620 Error(ERR_WARN, "cannot save level file '%s'", filename);
624 level.file_version = FILE_VERSION_ACTUAL;
625 level.game_version = GAME_VERSION_ACTUAL;
627 /* check level field for 16-bit elements */
628 level.encoding_16bit_field = FALSE;
629 for(y=0; y<level.fieldy; y++)
630 for(x=0; x<level.fieldx; x++)
632 level.encoding_16bit_field = TRUE;
634 /* check yamyam content for 16-bit elements */
635 level.encoding_16bit_yamyam = FALSE;
636 for(i=0; i<level.num_yam_contents; i++)
639 if (level.yam_content[i][x][y] > 255)
640 level.encoding_16bit_yamyam = TRUE;
642 /* check amoeba content for 16-bit elements */
643 level.encoding_16bit_amoeba = FALSE;
644 if (level.amoeba_content > 255)
645 level.encoding_16bit_amoeba = TRUE;
648 level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
650 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
651 putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
653 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
654 SaveLevel_VERS(file, &level);
656 putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
657 SaveLevel_HEAD(file, &level);
659 putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
660 SaveLevel_AUTH(file, &level);
662 putFileChunkBE(file, "BODY", body_chunk_size);
663 SaveLevel_BODY(file, &level);
665 if (level.encoding_16bit_yamyam ||
666 level.num_yam_contents != STD_ELEMENT_CONTENTS)
668 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
669 SaveLevel_CNT2(file, &level, EL_YAMYAM);
672 if (level.encoding_16bit_amoeba)
674 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
675 SaveLevel_CNT2(file, &level, EL_BD_AMOEBA);
680 SetFilePermissions(filename, PERMS_PRIVATE);
684 /* ========================================================================= */
685 /* tape file functions */
686 /* ========================================================================= */
688 static void setTapeInfoToDefaults()
692 /* always start with reliable default values (empty tape) */
695 /* default values (also for pre-1.2 tapes) with only the first player */
696 tape.player_participates[0] = TRUE;
697 for(i=1; i<MAX_PLAYERS; i++)
698 tape.player_participates[i] = FALSE;
700 /* at least one (default: the first) player participates in every tape */
701 tape.num_participating_players = 1;
703 tape.level_nr = level_nr;
705 tape.changed = FALSE;
707 tape.recording = FALSE;
708 tape.playing = FALSE;
709 tape.pausing = FALSE;
712 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
714 tape->file_version = getFileVersion(file);
715 tape->game_version = getFileVersion(file);
720 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
724 tape->random_seed = getFile32BitBE(file);
725 tape->date = getFile32BitBE(file);
726 tape->length = getFile32BitBE(file);
728 /* read header fields that are new since version 1.2 */
729 if (tape->file_version >= FILE_VERSION_1_2)
731 byte store_participating_players = fgetc(file);
734 /* since version 1.2, tapes store which players participate in the tape */
735 tape->num_participating_players = 0;
736 for(i=0; i<MAX_PLAYERS; i++)
738 tape->player_participates[i] = FALSE;
740 if (store_participating_players & (1 << i))
742 tape->player_participates[i] = TRUE;
743 tape->num_participating_players++;
747 ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
749 engine_version = getFileVersion(file);
750 if (engine_version > 0)
751 tape->engine_version = engine_version;
757 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
760 int chunk_size_expected =
761 (tape->num_participating_players + 1) * tape->length;
763 if (chunk_size_expected != chunk_size)
765 ReadUnusedBytesFromFile(file, chunk_size);
766 return chunk_size_expected;
769 for(i=0; i<tape->length; i++)
771 if (i >= MAX_TAPELEN)
774 for(j=0; j<MAX_PLAYERS; j++)
776 tape->pos[i].action[j] = MV_NO_MOVING;
778 if (tape->player_participates[j])
779 tape->pos[i].action[j] = fgetc(file);
782 tape->pos[i].delay = fgetc(file);
784 if (tape->file_version == FILE_VERSION_1_0)
786 /* eliminate possible diagonal moves in old tapes */
787 /* this is only for backward compatibility */
789 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
790 byte action = tape->pos[i].action[0];
791 int k, num_moves = 0;
795 if (action & joy_dir[k])
797 tape->pos[i + num_moves].action[0] = joy_dir[k];
799 tape->pos[i + num_moves].delay = 0;
808 tape->length += num_moves;
811 else if (tape->file_version < FILE_VERSION_2_0)
813 /* convert pre-2.0 tapes to new tape format */
815 if (tape->pos[i].delay > 1)
818 tape->pos[i + 1] = tape->pos[i];
819 tape->pos[i + 1].delay = 1;
822 for(j=0; j<MAX_PLAYERS; j++)
823 tape->pos[i].action[j] = MV_NO_MOVING;
824 tape->pos[i].delay--;
835 if (i != tape->length)
836 chunk_size = (tape->num_participating_players + 1) * i;
841 void LoadTape(int level_nr)
843 char *filename = getTapeFilename(level_nr);
844 char cookie[MAX_LINE_LEN];
845 char chunk_name[CHUNK_ID_LEN + 1];
849 /* always start with reliable default values */
850 setTapeInfoToDefaults();
852 if (!(file = fopen(filename, MODE_READ)))
855 getFileChunkBE(file, chunk_name, NULL);
856 if (strcmp(chunk_name, "RND1") == 0)
858 getFile32BitBE(file); /* not used */
860 getFileChunkBE(file, chunk_name, NULL);
861 if (strcmp(chunk_name, "TAPE") != 0)
863 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
868 else /* check for pre-2.0 file format with cookie string */
870 strcpy(cookie, chunk_name);
871 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
872 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
873 cookie[strlen(cookie) - 1] = '\0';
875 if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
877 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
882 if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
884 Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
889 /* pre-2.0 tape files have no game version, so use file version here */
890 tape.game_version = tape.file_version;
893 if (tape.file_version < FILE_VERSION_1_2)
895 /* tape files from versions before 1.2.0 without chunk structure */
896 LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
897 LoadTape_BODY(file, 2 * tape.length, &tape);
905 int (*loader)(FILE *, int, struct TapeInfo *);
909 { "VERS", FILE_VERS_CHUNK_SIZE, LoadTape_VERS },
910 { "HEAD", TAPE_HEADER_SIZE, LoadTape_HEAD },
911 { "BODY", -1, LoadTape_BODY },
915 while (getFileChunkBE(file, chunk_name, &chunk_size))
919 while (chunk_info[i].name != NULL &&
920 strcmp(chunk_name, chunk_info[i].name) != 0)
923 if (chunk_info[i].name == NULL)
925 Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
926 chunk_name, filename);
927 ReadUnusedBytesFromFile(file, chunk_size);
929 else if (chunk_info[i].size != -1 &&
930 chunk_info[i].size != chunk_size)
932 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
933 chunk_size, chunk_name, filename);
934 ReadUnusedBytesFromFile(file, chunk_size);
938 /* call function to load this tape chunk */
939 int chunk_size_expected =
940 (chunk_info[i].loader)(file, chunk_size, &tape);
942 /* the size of some chunks cannot be checked before reading other
943 chunks first (like "HEAD" and "BODY") that contain some header
944 information, so check them here */
945 if (chunk_size_expected != chunk_size)
947 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
948 chunk_size, chunk_name, filename);
956 tape.length_seconds = GetTapeLength();
959 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
961 putFileVersion(file, tape->file_version);
962 putFileVersion(file, tape->game_version);
965 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
968 byte store_participating_players = 0;
970 /* set bits for participating players for compact storage */
971 for(i=0; i<MAX_PLAYERS; i++)
972 if (tape->player_participates[i])
973 store_participating_players |= (1 << i);
975 putFile32BitBE(file, tape->random_seed);
976 putFile32BitBE(file, tape->date);
977 putFile32BitBE(file, tape->length);
979 fputc(store_participating_players, file);
981 /* unused bytes not at the end here for 4-byte alignment of engine_version */
982 WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
984 putFileVersion(file, tape->engine_version);
987 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
991 for(i=0; i<tape->length; i++)
993 for(j=0; j<MAX_PLAYERS; j++)
994 if (tape->player_participates[j])
995 fputc(tape->pos[i].action[j], file);
997 fputc(tape->pos[i].delay, file);
1001 void SaveTape(int level_nr)
1004 char *filename = getTapeFilename(level_nr);
1006 boolean new_tape = TRUE;
1007 int num_participating_players = 0;
1008 int body_chunk_size;
1010 InitTapeDirectory(leveldir_current->filename);
1012 /* if a tape still exists, ask to overwrite it */
1013 if (access(filename, F_OK) == 0)
1016 if (!Request("Replace old tape ?", REQ_ASK))
1020 if (!(file = fopen(filename, MODE_WRITE)))
1022 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
1026 tape.file_version = FILE_VERSION_ACTUAL;
1027 tape.game_version = GAME_VERSION_ACTUAL;
1029 /* count number of participating players */
1030 for(i=0; i<MAX_PLAYERS; i++)
1031 if (tape.player_participates[i])
1032 num_participating_players++;
1034 body_chunk_size = (num_participating_players + 1) * tape.length;
1036 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1037 putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
1039 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1040 SaveTape_VERS(file, &tape);
1042 putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
1043 SaveTape_HEAD(file, &tape);
1045 putFileChunkBE(file, "BODY", body_chunk_size);
1046 SaveTape_BODY(file, &tape);
1050 SetFilePermissions(filename, PERMS_PRIVATE);
1052 tape.changed = FALSE;
1055 Request("tape saved !", REQ_CONFIRM);
1058 void DumpTape(struct TapeInfo *tape)
1062 if (TAPE_IS_EMPTY(*tape))
1064 Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
1069 printf("-------------------------------------------------------------------------------\n");
1070 printf("Tape of Level %d (file version %06d, game version %06d)\n",
1071 tape->level_nr, tape->file_version, tape->game_version);
1072 printf("-------------------------------------------------------------------------------\n");
1074 for(i=0; i<tape->length; i++)
1076 if (i >= MAX_TAPELEN)
1079 for(j=0; j<MAX_PLAYERS; j++)
1081 if (tape->player_participates[j])
1083 int action = tape->pos[i].action[j];
1085 printf("%d:%02x ", j, action);
1086 printf("[%c%c%c%c|%c%c] - ",
1087 (action & JOY_LEFT ? '<' : ' '),
1088 (action & JOY_RIGHT ? '>' : ' '),
1089 (action & JOY_UP ? '^' : ' '),
1090 (action & JOY_DOWN ? 'v' : ' '),
1091 (action & JOY_BUTTON_1 ? '1' : ' '),
1092 (action & JOY_BUTTON_2 ? '2' : ' '));
1096 printf("(%03d)\n", tape->pos[i].delay);
1099 printf("-------------------------------------------------------------------------------\n");
1103 /* ========================================================================= */
1104 /* score file functions */
1105 /* ========================================================================= */
1107 void LoadScore(int level_nr)
1110 char *filename = getScoreFilename(level_nr);
1111 char cookie[MAX_LINE_LEN];
1112 char line[MAX_LINE_LEN];
1116 /* always start with reliable default values */
1117 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1119 strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
1120 highscore[i].Score = 0;
1123 if (!(file = fopen(filename, MODE_READ)))
1126 /* check file identifier */
1127 fgets(cookie, MAX_LINE_LEN, file);
1128 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1129 cookie[strlen(cookie) - 1] = '\0';
1131 if (!checkCookieString(cookie, SCORE_COOKIE))
1133 Error(ERR_WARN, "unknown format of score file '%s'", filename);
1138 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1140 fscanf(file, "%d", &highscore[i].Score);
1141 fgets(line, MAX_LINE_LEN, file);
1143 if (line[strlen(line) - 1] == '\n')
1144 line[strlen(line) - 1] = '\0';
1146 for (line_ptr = line; *line_ptr; line_ptr++)
1148 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
1150 strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
1151 highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
1160 void SaveScore(int level_nr)
1163 char *filename = getScoreFilename(level_nr);
1166 InitScoreDirectory(leveldir_current->filename);
1168 if (!(file = fopen(filename, MODE_WRITE)))
1170 Error(ERR_WARN, "cannot save score for level %d", level_nr);
1174 fprintf(file, "%s\n\n", SCORE_COOKIE);
1176 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1177 fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
1181 SetFilePermissions(filename, PERMS_PUBLIC);
1185 /* ========================================================================= */
1186 /* setup file functions */
1187 /* ========================================================================= */
1189 #define TOKEN_STR_PLAYER_PREFIX "player_"
1192 #define SETUP_TOKEN_PLAYER_NAME 0
1193 #define SETUP_TOKEN_SOUND 1
1194 #define SETUP_TOKEN_SOUND_LOOPS 2
1195 #define SETUP_TOKEN_SOUND_MUSIC 3
1196 #define SETUP_TOKEN_SOUND_SIMPLE 4
1197 #define SETUP_TOKEN_TOONS 5
1198 #define SETUP_TOKEN_SCROLL_DELAY 6
1199 #define SETUP_TOKEN_SOFT_SCROLLING 7
1200 #define SETUP_TOKEN_FADING 8
1201 #define SETUP_TOKEN_AUTORECORD 9
1202 #define SETUP_TOKEN_QUICK_DOORS 10
1203 #define SETUP_TOKEN_TEAM_MODE 11
1204 #define SETUP_TOKEN_HANDICAP 12
1205 #define SETUP_TOKEN_TIME_LIMIT 13
1206 #define SETUP_TOKEN_FULLSCREEN 14
1207 #define SETUP_TOKEN_ASK_ON_ESCAPE 15
1208 #define SETUP_TOKEN_GRAPHICS_SET 16
1209 #define SETUP_TOKEN_SOUNDS_SET 17
1210 #define SETUP_TOKEN_MUSIC_SET 18
1211 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 19
1212 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 20
1213 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 21
1215 #define NUM_GLOBAL_SETUP_TOKENS 22
1217 /* shortcut setup */
1218 #define SETUP_TOKEN_SAVE_GAME 0
1219 #define SETUP_TOKEN_LOAD_GAME 1
1220 #define SETUP_TOKEN_TOGGLE_PAUSE 2
1222 #define NUM_SHORTCUT_SETUP_TOKENS 3
1225 #define SETUP_TOKEN_USE_JOYSTICK 0
1226 #define SETUP_TOKEN_JOY_DEVICE_NAME 1
1227 #define SETUP_TOKEN_JOY_XLEFT 2
1228 #define SETUP_TOKEN_JOY_XMIDDLE 3
1229 #define SETUP_TOKEN_JOY_XRIGHT 4
1230 #define SETUP_TOKEN_JOY_YUPPER 5
1231 #define SETUP_TOKEN_JOY_YMIDDLE 6
1232 #define SETUP_TOKEN_JOY_YLOWER 7
1233 #define SETUP_TOKEN_JOY_SNAP 8
1234 #define SETUP_TOKEN_JOY_BOMB 9
1235 #define SETUP_TOKEN_KEY_LEFT 10
1236 #define SETUP_TOKEN_KEY_RIGHT 11
1237 #define SETUP_TOKEN_KEY_UP 12
1238 #define SETUP_TOKEN_KEY_DOWN 13
1239 #define SETUP_TOKEN_KEY_SNAP 14
1240 #define SETUP_TOKEN_KEY_BOMB 15
1242 #define NUM_PLAYER_SETUP_TOKENS 16
1244 static struct SetupInfo si;
1245 static struct SetupShortcutInfo ssi;
1246 static struct SetupInputInfo sii;
1248 static struct TokenInfo global_setup_tokens[] =
1251 { TYPE_STRING, &si.player_name, "player_name" },
1252 { TYPE_SWITCH, &si.sound, "sound" },
1253 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
1254 { TYPE_SWITCH, &si.sound_music, "background_music" },
1255 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
1256 { TYPE_SWITCH, &si.toons, "toons" },
1257 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
1258 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
1259 { TYPE_SWITCH, &si.fading, "screen_fading" },
1260 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
1261 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
1262 { TYPE_SWITCH, &si.team_mode, "team_mode" },
1263 { TYPE_SWITCH, &si.handicap, "handicap" },
1264 { TYPE_SWITCH, &si.time_limit, "time_limit" },
1265 { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
1266 { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
1267 { TYPE_STRING, &si.graphics_set, "graphics_set" },
1268 { TYPE_STRING, &si.sounds_set, "sounds_set" },
1269 { TYPE_STRING, &si.music_set, "music_set" },
1270 { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
1271 { TYPE_SWITCH, &si.override_level_sounds, "override_level_sounds" },
1272 { TYPE_SWITCH, &si.override_level_music, "override_level_music" },
1275 static struct TokenInfo shortcut_setup_tokens[] =
1277 /* shortcut setup */
1278 { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
1279 { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
1280 { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }
1283 static struct TokenInfo player_setup_tokens[] =
1286 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
1287 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
1288 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
1289 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
1290 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
1291 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
1292 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
1293 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
1294 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
1295 { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
1296 { TYPE_KEY_X11, &sii.key.left, ".key.move_left" },
1297 { TYPE_KEY_X11, &sii.key.right, ".key.move_right" },
1298 { TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
1299 { TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
1300 { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
1301 { TYPE_KEY_X11, &sii.key.bomb, ".key.place_bomb" }
1304 static void setSetupInfoToDefaults(struct SetupInfo *si)
1308 si->player_name = getStringCopy(getLoginName());
1311 si->sound_loops = TRUE;
1312 si->sound_music = TRUE;
1313 si->sound_simple = TRUE;
1315 si->double_buffering = TRUE;
1316 si->direct_draw = !si->double_buffering;
1317 si->scroll_delay = TRUE;
1318 si->soft_scrolling = TRUE;
1320 si->autorecord = TRUE;
1321 si->quick_doors = FALSE;
1322 si->team_mode = FALSE;
1323 si->handicap = TRUE;
1324 si->time_limit = TRUE;
1325 si->fullscreen = FALSE;
1326 si->ask_on_escape = TRUE;
1328 si->graphics_set = getStringCopy(GRAPHICS_SUBDIR);
1329 si->sounds_set = getStringCopy(SOUNDS_SUBDIR);
1330 si->music_set = getStringCopy(MUSIC_SUBDIR);
1331 si->override_level_graphics = FALSE;
1332 si->override_level_sounds = FALSE;
1333 si->override_level_music = FALSE;
1335 si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
1336 si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
1337 si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
1339 for (i=0; i<MAX_PLAYERS; i++)
1341 si->input[i].use_joystick = FALSE;
1342 si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
1343 si->input[i].joy.xleft = JOYSTICK_XLEFT;
1344 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1345 si->input[i].joy.xright = JOYSTICK_XRIGHT;
1346 si->input[i].joy.yupper = JOYSTICK_YUPPER;
1347 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1348 si->input[i].joy.ylower = JOYSTICK_YLOWER;
1349 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
1350 si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
1351 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
1352 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
1353 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
1354 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
1355 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
1356 si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED);
1360 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
1364 if (!setup_file_list)
1369 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1370 setSetupInfo(global_setup_tokens, i,
1371 getTokenValue(setup_file_list, global_setup_tokens[i].text));
1374 /* shortcut setup */
1375 ssi = setup.shortcut;
1376 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1377 setSetupInfo(shortcut_setup_tokens, i,
1378 getTokenValue(setup_file_list,shortcut_setup_tokens[i].text));
1379 setup.shortcut = ssi;
1382 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1386 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1388 sii = setup.input[pnr];
1389 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1391 char full_token[100];
1393 sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
1394 setSetupInfo(player_setup_tokens, i,
1395 getTokenValue(setup_file_list, full_token));
1397 setup.input[pnr] = sii;
1403 char *filename = getSetupFilename();
1404 struct SetupFileList *setup_file_list = NULL;
1406 /* always start with reliable default values */
1407 setSetupInfoToDefaults(&setup);
1409 setup_file_list = loadSetupFileList(filename);
1411 if (setup_file_list)
1413 checkSetupFileListIdentifier(setup_file_list, getCookie("SETUP"));
1414 decodeSetupFileList(setup_file_list);
1416 setup.direct_draw = !setup.double_buffering;
1418 freeSetupFileList(setup_file_list);
1420 /* needed to work around problems with fixed length strings */
1421 if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN)
1422 setup.player_name[MAX_PLAYER_NAME_LEN] = '\0';
1423 else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN)
1425 char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
1427 strcpy(new_name, setup.player_name);
1428 free(setup.player_name);
1429 setup.player_name = new_name;
1433 Error(ERR_WARN, "using default setup values");
1438 char *filename = getSetupFilename();
1442 InitUserDataDirectory();
1444 if (!(file = fopen(filename, MODE_WRITE)))
1446 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1450 fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
1451 getCookie("SETUP")));
1452 fprintf(file, "\n");
1456 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1458 fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
1460 /* just to make things nicer :) */
1461 if (i == SETUP_TOKEN_PLAYER_NAME || i == SETUP_TOKEN_GRAPHICS_SET - 1)
1462 fprintf(file, "\n");
1465 /* shortcut setup */
1466 ssi = setup.shortcut;
1467 fprintf(file, "\n");
1468 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1469 fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
1472 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1476 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1477 fprintf(file, "\n");
1479 sii = setup.input[pnr];
1480 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1481 fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
1486 SetFilePermissions(filename, PERMS_PRIVATE);