1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2001 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 7 /* 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 static void setLevelInfoToDefaults()
45 level.file_version = FILE_VERSION_ACTUAL;
46 level.game_version = GAME_VERSION_ACTUAL;
48 level.encoding_16bit_field = FALSE; /* default: only 8-bit elements */
49 level.encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
50 level.encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
52 lev_fieldx = level.fieldx = STD_LEV_FIELDX;
53 lev_fieldy = level.fieldy = STD_LEV_FIELDY;
55 for(x=0; x<MAX_LEV_FIELDX; x++)
56 for(y=0; y<MAX_LEV_FIELDY; y++)
57 Feld[x][y] = Ur[x][y] = EL_ERDREICH;
60 level.gems_needed = 0;
61 level.amoeba_speed = 10;
62 level.time_magic_wall = 10;
63 level.time_wheel = 10;
64 level.time_light = 10;
65 level.time_timegate = 10;
66 level.amoeba_content = EL_DIAMANT;
67 level.double_speed = FALSE;
68 level.gravity = FALSE;
69 level.em_slippery_gems = FALSE;
71 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
73 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
74 level.author[i] = '\0';
76 strcpy(level.name, NAMELESS_LEVEL_NAME);
77 strcpy(level.author, ANONYMOUS_NAME);
79 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
82 level.num_yam_contents = STD_ELEMENT_CONTENTS;
83 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
86 level.yam_content[i][x][y] =
87 (i < STD_ELEMENT_CONTENTS ? EL_FELSBROCKEN : EL_LEERRAUM);
89 Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
90 Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
91 Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_AUSGANG_ZU;
93 BorderElement = EL_BETON;
95 /* try to determine better author name than 'anonymous' */
96 if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
98 strncpy(level.author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
99 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
103 switch (LEVELCLASS(leveldir_current))
105 case LEVELCLASS_TUTORIAL:
106 strcpy(level.author, PROGRAM_AUTHOR_STRING);
109 case LEVELCLASS_CONTRIBUTION:
110 strncpy(level.author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN);
111 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
114 case LEVELCLASS_USER:
115 strncpy(level.author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
116 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
120 /* keep default value */
126 static int checkLevelElement(int element)
128 if (element >= EL_FIRST_RUNTIME_EL)
130 Error(ERR_WARN, "invalid level element %d", element);
131 element = EL_CHAR_FRAGE;
137 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
139 ReadChunk_VERS(file, &(level->file_version), &(level->game_version));
144 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
148 lev_fieldx = level->fieldx = fgetc(file);
149 lev_fieldy = level->fieldy = fgetc(file);
151 level->time = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
152 level->gems_needed = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
154 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
155 level->name[i] = fgetc(file);
156 level->name[MAX_LEVEL_NAME_LEN] = 0;
158 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
159 level->score[i] = fgetc(file);
161 level->num_yam_contents = STD_ELEMENT_CONTENTS;
162 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
165 level->yam_content[i][x][y] = checkLevelElement(fgetc(file));
167 level->amoeba_speed = fgetc(file);
168 level->time_magic_wall = fgetc(file);
169 level->time_wheel = fgetc(file);
170 level->amoeba_content = checkLevelElement(fgetc(file));
171 level->double_speed = (fgetc(file) == 1 ? TRUE : FALSE);
172 level->gravity = (fgetc(file) == 1 ? TRUE : FALSE);
173 level->encoding_16bit_field = (fgetc(file) == 1 ? TRUE : FALSE);
174 level->em_slippery_gems = (fgetc(file) == 1 ? TRUE : FALSE);
176 ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
181 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
185 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
186 level->author[i] = fgetc(file);
187 level->author[MAX_LEVEL_NAME_LEN] = 0;
192 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
196 int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
197 int chunk_size_expected = header_size + content_size;
199 /* Note: "chunk_size" was wrong before version 2.0 when elements are
200 stored with 16-bit encoding (and should be twice as big then).
201 Even worse, playfield data was stored 16-bit when only yamyam content
202 contained 16-bit elements and vice versa. */
204 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
205 chunk_size_expected += content_size;
207 if (chunk_size_expected != chunk_size)
209 ReadUnusedBytesFromFile(file, chunk_size);
210 return chunk_size_expected;
214 level->num_yam_contents = fgetc(file);
218 /* correct invalid number of content fields -- should never happen */
219 if (level->num_yam_contents < 1 ||
220 level->num_yam_contents > MAX_ELEMENT_CONTENTS)
221 level->num_yam_contents = STD_ELEMENT_CONTENTS;
223 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
226 level->yam_content[i][x][y] =
227 checkLevelElement(level->encoding_16bit_field ?
228 getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN) :
233 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
236 int chunk_size_expected = level->fieldx * level->fieldy;
238 /* Note: "chunk_size" was wrong before version 2.0 when elements are
239 stored with 16-bit encoding (and should be twice as big then).
240 Even worse, playfield data was stored 16-bit when only yamyam content
241 contained 16-bit elements and vice versa. */
243 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
244 chunk_size_expected *= 2;
246 if (chunk_size_expected != chunk_size)
248 ReadUnusedBytesFromFile(file, chunk_size);
249 return chunk_size_expected;
252 for(y=0; y<level->fieldy; y++)
253 for(x=0; x<level->fieldx; x++)
254 Feld[x][y] = Ur[x][y] =
255 checkLevelElement(level->encoding_16bit_field ?
256 getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN) :
261 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
265 int num_contents, content_xsize, content_ysize;
266 int content_array[MAX_ELEMENT_CONTENTS][3][3];
268 element = checkLevelElement(getFile16BitInteger(file,BYTE_ORDER_BIG_ENDIAN));
269 num_contents = fgetc(file);
270 content_xsize = fgetc(file);
271 content_ysize = fgetc(file);
272 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
274 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
277 content_array[i][x][y] =
278 checkLevelElement(getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN));
280 /* correct invalid number of content fields -- should never happen */
281 if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
282 num_contents = STD_ELEMENT_CONTENTS;
284 if (element == EL_MAMPFER)
286 level->num_yam_contents = num_contents;
288 for(i=0; i<num_contents; i++)
291 level->yam_content[i][x][y] = content_array[i][x][y];
293 else if (element == EL_AMOEBE_BD)
295 level->amoeba_content = content_array[0][0][0];
299 Error(ERR_WARN, "cannot load content for element '%d'", element);
305 void LoadLevel(int level_nr)
307 char *filename = getLevelFilename(level_nr);
308 char cookie[MAX_LINE_LEN];
309 char chunk_name[CHUNK_ID_LEN + 1];
313 /* always start with reliable default values */
314 setLevelInfoToDefaults();
316 if (!(file = fopen(filename, MODE_READ)))
318 Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
322 getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
323 if (strcmp(chunk_name, "RND1") == 0)
325 getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN); /* not used */
327 getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
328 if (strcmp(chunk_name, "CAVE") != 0)
330 Error(ERR_WARN, "unknown format of level file '%s'", filename);
335 else /* check for pre-2.0 file format with cookie string */
337 strcpy(cookie, chunk_name);
338 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
339 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
340 cookie[strlen(cookie) - 1] = '\0';
342 if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
344 Error(ERR_WARN, "unknown format of level file '%s'", filename);
349 if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
351 Error(ERR_WARN, "unsupported version of level file '%s'", filename);
356 /* pre-2.0 level files have no game version, so use file version here */
357 level.game_version = level.file_version;
360 if (level.file_version < FILE_VERSION_1_2)
362 /* level files from versions before 1.2.0 without chunk structure */
363 LoadLevel_HEAD(file, LEVEL_HEADER_SIZE, &level);
364 LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
372 int (*loader)(FILE *, int, struct LevelInfo *);
376 { "VERS", FILE_VERS_CHUNK_SIZE, LoadLevel_VERS },
377 { "HEAD", LEVEL_HEADER_SIZE, LoadLevel_HEAD },
378 { "AUTH", MAX_LEVEL_AUTHOR_LEN, LoadLevel_AUTH },
379 { "CONT", -1, LoadLevel_CONT },
380 { "BODY", -1, LoadLevel_BODY },
381 { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
385 while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_BIG_ENDIAN))
389 while (chunk_info[i].name != NULL &&
390 strcmp(chunk_name, chunk_info[i].name) != 0)
393 if (chunk_info[i].name == NULL)
395 Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
396 chunk_name, filename);
397 ReadUnusedBytesFromFile(file, chunk_size);
399 else if (chunk_info[i].size != -1 &&
400 chunk_info[i].size != chunk_size)
402 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
403 chunk_size, chunk_name, filename);
404 ReadUnusedBytesFromFile(file, chunk_size);
408 /* call function to load this level chunk */
409 int chunk_size_expected =
410 (chunk_info[i].loader)(file, chunk_size, &level);
412 /* the size of some chunks cannot be checked before reading other
413 chunks first (like "HEAD" and "BODY") that contain some header
414 information, so check them here */
415 if (chunk_size_expected != chunk_size)
417 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
418 chunk_size, chunk_name, filename);
426 if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
427 IS_LEVELCLASS_USER(leveldir_current))
429 /* For user contributed and private levels, use the version of
430 the game engine the levels were created for.
431 Since 2.0.1, the game engine version is now directly stored
432 in the level file (chunk "VERS"), so there is no need anymore
433 to set the game version from the file version (except for old,
434 pre-2.0 levels, where the game version is still taken from the
435 file format version used to store the level -- see above). */
437 /* do some special adjustments to support older level versions */
438 if (level.file_version == FILE_VERSION_1_0)
440 Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
441 Error(ERR_WARN, "using high speed movement for player");
443 /* player was faster than monsters in (pre-)1.0 levels */
444 level.double_speed = TRUE;
449 /* Always use the latest version of the game engine for all but
450 user contributed and private levels; this allows for actual
451 corrections in the game engine to take effect for existing,
452 converted levels (from "classic" or other existing games) to
453 make the game emulation more accurate, while (hopefully) not
454 breaking existing levels created from other players. */
456 level.game_version = GAME_VERSION_ACTUAL;
458 /* Set special EM style gems behaviour: EM style gems slip down from
459 normal, steel and growing wall. As this is a more fundamental change,
460 it seems better to set the default behaviour to "off" (as it is more
461 natural) and make it configurable in the level editor (as a property
462 of gem style elements). Already existing converted levels (neither
463 private nor contributed levels) are changed to the new behaviour. */
465 if (level.file_version < FILE_VERSION_2_0)
466 level.em_slippery_gems = TRUE;
469 /* determine border element for this level */
473 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
477 fputc(level->fieldx, file);
478 fputc(level->fieldy, file);
480 putFile16BitInteger(file, level->time, BYTE_ORDER_BIG_ENDIAN);
481 putFile16BitInteger(file, level->gems_needed, BYTE_ORDER_BIG_ENDIAN);
483 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
484 fputc(level->name[i], file);
486 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
487 fputc(level->score[i], file);
489 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
492 fputc((level->encoding_16bit_yamyam ? EL_LEERRAUM :
493 level->yam_content[i][x][y]),
495 fputc(level->amoeba_speed, file);
496 fputc(level->time_magic_wall, file);
497 fputc(level->time_wheel, file);
498 fputc((level->encoding_16bit_amoeba ? EL_LEERRAUM : level->amoeba_content),
500 fputc((level->double_speed ? 1 : 0), file);
501 fputc((level->gravity ? 1 : 0), file);
502 fputc((level->encoding_16bit_field ? 1 : 0), file);
503 fputc((level->em_slippery_gems ? 1 : 0), file);
505 WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
508 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
512 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
513 fputc(level->author[i], file);
517 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
521 fputc(EL_MAMPFER, file);
522 fputc(level->num_yam_contents, file);
526 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
529 if (level->encoding_16bit_field)
530 putFile16BitInteger(file, level->yam_content[i][x][y],
531 BYTE_ORDER_BIG_ENDIAN);
533 fputc(level->yam_content[i][x][y], file);
537 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
541 for(y=0; y<level->fieldy; y++)
542 for(x=0; x<level->fieldx; x++)
543 if (level->encoding_16bit_field)
544 putFile16BitInteger(file, Ur[x][y], BYTE_ORDER_BIG_ENDIAN);
546 fputc(Ur[x][y], file);
549 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
552 int num_contents, content_xsize, content_ysize;
553 int content_array[MAX_ELEMENT_CONTENTS][3][3];
555 if (element == EL_MAMPFER)
557 num_contents = level->num_yam_contents;
561 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
564 content_array[i][x][y] = level->yam_content[i][x][y];
566 else if (element == EL_AMOEBE_BD)
572 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
575 content_array[i][x][y] = EL_LEERRAUM;
576 content_array[0][0][0] = level->amoeba_content;
580 /* chunk header already written -- write empty chunk data */
581 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
583 Error(ERR_WARN, "cannot save content for element '%d'", element);
587 putFile16BitInteger(file, element, BYTE_ORDER_BIG_ENDIAN);
588 fputc(num_contents, file);
589 fputc(content_xsize, file);
590 fputc(content_ysize, file);
592 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
594 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
597 putFile16BitInteger(file, content_array[i][x][y],
598 BYTE_ORDER_BIG_ENDIAN);
601 void SaveLevel(int level_nr)
604 char *filename = getLevelFilename(level_nr);
608 if (!(file = fopen(filename, MODE_WRITE)))
610 Error(ERR_WARN, "cannot save level file '%s'", filename);
615 /* check level field for 16-bit elements */
616 level.encoding_16bit_field = FALSE;
617 for(y=0; y<level.fieldy; y++)
618 for(x=0; x<level.fieldx; x++)
620 level.encoding_16bit_field = TRUE;
622 /* check yamyam content for 16-bit elements */
623 level.encoding_16bit_yamyam = FALSE;
624 for(i=0; i<level.num_yam_contents; i++)
627 if (level.yam_content[i][x][y] > 255)
628 level.encoding_16bit_yamyam = TRUE;
630 /* check amoeba content for 16-bit elements */
631 level.encoding_16bit_amoeba = FALSE;
632 if (level.amoeba_content > 255)
633 level.encoding_16bit_amoeba = TRUE;
636 level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
638 putFileChunk(file, "RND1", CHUNK_SIZE_UNDEFINED, BYTE_ORDER_BIG_ENDIAN);
639 putFileChunk(file, "CAVE", CHUNK_SIZE_NONE, BYTE_ORDER_BIG_ENDIAN);
641 putFileChunk(file, "VERS", FILE_VERS_CHUNK_SIZE, BYTE_ORDER_BIG_ENDIAN);
642 WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
644 putFileChunk(file, "HEAD", LEVEL_HEADER_SIZE, BYTE_ORDER_BIG_ENDIAN);
645 SaveLevel_HEAD(file, &level);
647 putFileChunk(file, "AUTH", MAX_LEVEL_AUTHOR_LEN, BYTE_ORDER_BIG_ENDIAN);
648 SaveLevel_AUTH(file, &level);
650 putFileChunk(file, "BODY", body_chunk_size, BYTE_ORDER_BIG_ENDIAN);
651 SaveLevel_BODY(file, &level);
653 if (level.encoding_16bit_yamyam ||
654 level.num_yam_contents != STD_ELEMENT_CONTENTS)
656 putFileChunk(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE, BYTE_ORDER_BIG_ENDIAN);
657 SaveLevel_CNT2(file, &level, EL_MAMPFER);
660 if (level.encoding_16bit_amoeba)
662 putFileChunk(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE, BYTE_ORDER_BIG_ENDIAN);
663 SaveLevel_CNT2(file, &level, EL_AMOEBE_BD);
668 SetFilePermissions(filename, PERMS_PRIVATE);
671 static void setTapeInfoToDefaults()
675 /* always start with reliable default values (empty tape) */
676 tape.file_version = FILE_VERSION_ACTUAL;
677 tape.game_version = GAME_VERSION_ACTUAL;
680 /* default values (also for pre-1.2 tapes) with only the first player */
681 tape.player_participates[0] = TRUE;
682 for(i=1; i<MAX_PLAYERS; i++)
683 tape.player_participates[i] = FALSE;
685 /* at least one (default: the first) player participates in every tape */
686 tape.num_participating_players = 1;
688 tape.level_nr = level_nr;
690 tape.changed = FALSE;
692 tape.recording = FALSE;
693 tape.playing = FALSE;
694 tape.pausing = FALSE;
697 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
699 ReadChunk_VERS(file, &(tape->file_version), &(tape->game_version));
704 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
708 tape->random_seed = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
709 tape->date = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
710 tape->length = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
712 /* read header fields that are new since version 1.2 */
713 if (tape->file_version >= FILE_VERSION_1_2)
715 byte store_participating_players = fgetc(file);
717 ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
719 /* since version 1.2, tapes store which players participate in the tape */
720 tape->num_participating_players = 0;
721 for(i=0; i<MAX_PLAYERS; i++)
723 tape->player_participates[i] = FALSE;
725 if (store_participating_players & (1 << i))
727 tape->player_participates[i] = TRUE;
728 tape->num_participating_players++;
736 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
739 int chunk_size_expected =
740 (tape->num_participating_players + 1) * tape->length;
742 if (chunk_size_expected != chunk_size)
744 ReadUnusedBytesFromFile(file, chunk_size);
745 return chunk_size_expected;
748 for(i=0; i<tape->length; i++)
750 if (i >= MAX_TAPELEN)
753 for(j=0; j<MAX_PLAYERS; j++)
755 tape->pos[i].action[j] = MV_NO_MOVING;
757 if (tape->player_participates[j])
758 tape->pos[i].action[j] = fgetc(file);
761 tape->pos[i].delay = fgetc(file);
763 if (tape->file_version == FILE_VERSION_1_0)
765 /* eliminate possible diagonal moves in old tapes */
766 /* this is only for backward compatibility */
768 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
769 byte action = tape->pos[i].action[0];
770 int k, num_moves = 0;
774 if (action & joy_dir[k])
776 tape->pos[i + num_moves].action[0] = joy_dir[k];
778 tape->pos[i + num_moves].delay = 0;
787 tape->length += num_moves;
790 else if (tape->file_version < FILE_VERSION_2_0)
792 if (tape->pos[i].delay > 1)
795 tape->pos[i + 1] = tape->pos[i];
796 tape->pos[i + 1].delay = 1;
799 for(j=0; j<MAX_PLAYERS; j++)
800 tape->pos[i].action[j] = MV_NO_MOVING;
801 tape->pos[i].delay--;
812 if (i != tape->length)
813 chunk_size = (tape->num_participating_players + 1) * i;
818 void LoadTape(int level_nr)
820 char *filename = getTapeFilename(level_nr);
821 char cookie[MAX_LINE_LEN];
822 char chunk_name[CHUNK_ID_LEN + 1];
826 /* always start with reliable default values */
827 setTapeInfoToDefaults();
829 if (!(file = fopen(filename, MODE_READ)))
832 getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
833 if (strcmp(chunk_name, "RND1") == 0)
835 getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN); /* not used */
837 getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
838 if (strcmp(chunk_name, "TAPE") != 0)
840 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
845 else /* check for pre-2.0 file format with cookie string */
847 strcpy(cookie, chunk_name);
848 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
849 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
850 cookie[strlen(cookie) - 1] = '\0';
852 if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
854 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
859 if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
861 Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
866 /* pre-2.0 tape files have no game version, so use file version here */
867 tape.game_version = tape.file_version;
870 if (tape.file_version < FILE_VERSION_1_2)
872 /* tape files from versions before 1.2.0 without chunk structure */
873 LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
874 LoadTape_BODY(file, 2 * tape.length, &tape);
882 int (*loader)(FILE *, int, struct TapeInfo *);
886 { "VERS", FILE_VERS_CHUNK_SIZE, LoadTape_VERS },
887 { "HEAD", TAPE_HEADER_SIZE, LoadTape_HEAD },
888 { "BODY", -1, LoadTape_BODY },
892 while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_BIG_ENDIAN))
896 while (chunk_info[i].name != NULL &&
897 strcmp(chunk_name, chunk_info[i].name) != 0)
900 if (chunk_info[i].name == NULL)
902 Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
903 chunk_name, filename);
904 ReadUnusedBytesFromFile(file, chunk_size);
906 else if (chunk_info[i].size != -1 &&
907 chunk_info[i].size != chunk_size)
909 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
910 chunk_size, chunk_name, filename);
911 ReadUnusedBytesFromFile(file, chunk_size);
915 /* call function to load this tape chunk */
916 int chunk_size_expected =
917 (chunk_info[i].loader)(file, chunk_size, &tape);
919 /* the size of some chunks cannot be checked before reading other
920 chunks first (like "HEAD" and "BODY") that contain some header
921 information, so check them here */
922 if (chunk_size_expected != chunk_size)
924 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
925 chunk_size, chunk_name, filename);
933 tape.length_seconds = GetTapeLength();
936 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
939 byte store_participating_players = 0;
941 /* set bits for participating players for compact storage */
942 for(i=0; i<MAX_PLAYERS; i++)
943 if (tape->player_participates[i])
944 store_participating_players |= (1 << i);
946 putFile32BitInteger(file, tape->random_seed, BYTE_ORDER_BIG_ENDIAN);
947 putFile32BitInteger(file, tape->date, BYTE_ORDER_BIG_ENDIAN);
948 putFile32BitInteger(file, tape->length, BYTE_ORDER_BIG_ENDIAN);
950 fputc(store_participating_players, file);
952 WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
955 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
959 for(i=0; i<tape->length; i++)
961 for(j=0; j<MAX_PLAYERS; j++)
962 if (tape->player_participates[j])
963 fputc(tape->pos[i].action[j], file);
965 fputc(tape->pos[i].delay, file);
969 void SaveTape(int level_nr)
972 char *filename = getTapeFilename(level_nr);
974 boolean new_tape = TRUE;
975 int num_participating_players = 0;
978 InitTapeDirectory(leveldir_current->filename);
980 /* if a tape still exists, ask to overwrite it */
981 if (access(filename, F_OK) == 0)
984 if (!Request("Replace old tape ?", REQ_ASK))
988 if (!(file = fopen(filename, MODE_WRITE)))
990 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
994 /* count number of participating players */
995 for(i=0; i<MAX_PLAYERS; i++)
996 if (tape.player_participates[i])
997 num_participating_players++;
999 body_chunk_size = (num_participating_players + 1) * tape.length;
1001 putFileChunk(file, "RND1", CHUNK_SIZE_UNDEFINED, BYTE_ORDER_BIG_ENDIAN);
1002 putFileChunk(file, "TAPE", CHUNK_SIZE_NONE, BYTE_ORDER_BIG_ENDIAN);
1004 putFileChunk(file, "VERS", FILE_VERS_CHUNK_SIZE, BYTE_ORDER_BIG_ENDIAN);
1005 WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
1007 putFileChunk(file, "HEAD", TAPE_HEADER_SIZE, BYTE_ORDER_BIG_ENDIAN);
1008 SaveTape_HEAD(file, &tape);
1010 putFileChunk(file, "BODY", body_chunk_size, BYTE_ORDER_BIG_ENDIAN);
1011 SaveTape_BODY(file, &tape);
1015 SetFilePermissions(filename, PERMS_PRIVATE);
1017 tape.changed = FALSE;
1020 Request("tape saved !", REQ_CONFIRM);
1023 void DumpTape(struct TapeInfo *tape)
1027 if (TAPE_IS_EMPTY(*tape))
1029 Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
1034 printf("-------------------------------------------------------------------------------\n");
1035 printf("Tape of Level %d (file version %06d, game version %06d\n",
1036 tape->level_nr, tape->file_version, tape->game_version);
1037 printf("-------------------------------------------------------------------------------\n");
1039 for(i=0; i<tape->length; i++)
1041 if (i >= MAX_TAPELEN)
1044 for(j=0; j<MAX_PLAYERS; j++)
1046 if (tape->player_participates[j])
1048 int action = tape->pos[i].action[j];
1050 printf("%d:%02x ", j, action);
1051 printf("[%c%c%c%c|%c%c] - ",
1052 (action & JOY_LEFT ? '<' : ' '),
1053 (action & JOY_RIGHT ? '>' : ' '),
1054 (action & JOY_UP ? '^' : ' '),
1055 (action & JOY_DOWN ? 'v' : ' '),
1056 (action & JOY_BUTTON_1 ? '1' : ' '),
1057 (action & JOY_BUTTON_2 ? '2' : ' '));
1061 printf("(%03d)\n", tape->pos[i].delay);
1064 printf("-------------------------------------------------------------------------------\n");
1067 void LoadScore(int level_nr)
1070 char *filename = getScoreFilename(level_nr);
1071 char cookie[MAX_LINE_LEN];
1072 char line[MAX_LINE_LEN];
1076 /* always start with reliable default values */
1077 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1079 strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
1080 highscore[i].Score = 0;
1083 if (!(file = fopen(filename, MODE_READ)))
1086 /* check file identifier */
1087 fgets(cookie, MAX_LINE_LEN, file);
1088 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1089 cookie[strlen(cookie) - 1] = '\0';
1091 if (!checkCookieString(cookie, SCORE_COOKIE))
1093 Error(ERR_WARN, "unknown format of score file '%s'", filename);
1098 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1100 fscanf(file, "%d", &highscore[i].Score);
1101 fgets(line, MAX_LINE_LEN, file);
1103 if (line[strlen(line) - 1] == '\n')
1104 line[strlen(line) - 1] = '\0';
1106 for (line_ptr = line; *line_ptr; line_ptr++)
1108 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
1110 strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
1111 highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
1120 void SaveScore(int level_nr)
1123 char *filename = getScoreFilename(level_nr);
1126 InitScoreDirectory(leveldir_current->filename);
1128 if (!(file = fopen(filename, MODE_WRITE)))
1130 Error(ERR_WARN, "cannot save score for level %d", level_nr);
1134 fprintf(file, "%s\n\n", SCORE_COOKIE);
1136 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1137 fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
1141 SetFilePermissions(filename, PERMS_PUBLIC);