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 /* ========================================================================= */
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_ERDREICH;
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_DIAMANT;
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_FELSBROCKEN : EL_LEERRAUM);
93 Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
94 Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
95 Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_AUSGANG_ZU;
97 BorderElement = EL_BETON;
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_EL)
134 Error(ERR_WARN, "invalid level element %d", element);
135 element = EL_CHAR_FRAGE;
141 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
143 ReadChunk_VERS(file, &(level->file_version), &(level->game_version));
148 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
152 lev_fieldx = level->fieldx = fgetc(file);
153 lev_fieldy = level->fieldy = fgetc(file);
155 level->time = getFile16BitBE(file);
156 level->gems_needed = getFile16BitBE(file);
158 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
159 level->name[i] = fgetc(file);
160 level->name[MAX_LEVEL_NAME_LEN] = 0;
162 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
163 level->score[i] = fgetc(file);
165 level->num_yam_contents = STD_ELEMENT_CONTENTS;
166 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
169 level->yam_content[i][x][y] = checkLevelElement(fgetc(file));
171 level->amoeba_speed = fgetc(file);
172 level->time_magic_wall = fgetc(file);
173 level->time_wheel = fgetc(file);
174 level->amoeba_content = checkLevelElement(fgetc(file));
175 level->double_speed = (fgetc(file) == 1 ? TRUE : FALSE);
176 level->gravity = (fgetc(file) == 1 ? TRUE : FALSE);
177 level->encoding_16bit_field = (fgetc(file) == 1 ? TRUE : FALSE);
178 level->em_slippery_gems = (fgetc(file) == 1 ? TRUE : FALSE);
180 ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
185 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
189 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
190 level->author[i] = fgetc(file);
191 level->author[MAX_LEVEL_NAME_LEN] = 0;
196 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
200 int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
201 int chunk_size_expected = header_size + content_size;
203 /* Note: "chunk_size" was wrong before version 2.0 when elements are
204 stored with 16-bit encoding (and should be twice as big then).
205 Even worse, playfield data was stored 16-bit when only yamyam content
206 contained 16-bit elements and vice versa. */
208 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
209 chunk_size_expected += content_size;
211 if (chunk_size_expected != chunk_size)
213 ReadUnusedBytesFromFile(file, chunk_size);
214 return chunk_size_expected;
218 level->num_yam_contents = fgetc(file);
222 /* correct invalid number of content fields -- should never happen */
223 if (level->num_yam_contents < 1 ||
224 level->num_yam_contents > MAX_ELEMENT_CONTENTS)
225 level->num_yam_contents = STD_ELEMENT_CONTENTS;
227 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
230 level->yam_content[i][x][y] =
231 checkLevelElement(level->encoding_16bit_field ?
232 getFile16BitBE(file) : fgetc(file));
236 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
239 int chunk_size_expected = level->fieldx * level->fieldy;
241 /* Note: "chunk_size" was wrong before version 2.0 when elements are
242 stored with 16-bit encoding (and should be twice as big then).
243 Even worse, playfield data was stored 16-bit when only yamyam content
244 contained 16-bit elements and vice versa. */
246 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
247 chunk_size_expected *= 2;
249 if (chunk_size_expected != chunk_size)
251 ReadUnusedBytesFromFile(file, chunk_size);
252 return chunk_size_expected;
255 for(y=0; y<level->fieldy; y++)
256 for(x=0; x<level->fieldx; x++)
257 Feld[x][y] = Ur[x][y] =
258 checkLevelElement(level->encoding_16bit_field ?
259 getFile16BitBE(file) : fgetc(file));
263 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
267 int num_contents, content_xsize, content_ysize;
268 int content_array[MAX_ELEMENT_CONTENTS][3][3];
270 element = checkLevelElement(getFile16BitBE(file));
271 num_contents = fgetc(file);
272 content_xsize = fgetc(file);
273 content_ysize = fgetc(file);
274 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
276 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
279 content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
281 /* correct invalid number of content fields -- should never happen */
282 if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
283 num_contents = STD_ELEMENT_CONTENTS;
285 if (element == EL_MAMPFER)
287 level->num_yam_contents = num_contents;
289 for(i=0; i<num_contents; i++)
292 level->yam_content[i][x][y] = content_array[i][x][y];
294 else if (element == EL_AMOEBE_BD)
296 level->amoeba_content = content_array[0][0][0];
300 Error(ERR_WARN, "cannot load content for element '%d'", element);
306 void LoadLevel(int level_nr)
308 char *filename = getLevelFilename(level_nr);
309 char cookie[MAX_LINE_LEN];
310 char chunk_name[CHUNK_ID_LEN + 1];
314 /* always start with reliable default values */
315 setLevelInfoToDefaults();
317 if (!(file = fopen(filename, MODE_READ)))
319 Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
323 getFileChunkBE(file, chunk_name, NULL);
324 if (strcmp(chunk_name, "RND1") == 0)
326 getFile32BitBE(file); /* not used */
328 getFileChunkBE(file, chunk_name, NULL);
329 if (strcmp(chunk_name, "CAVE") != 0)
331 Error(ERR_WARN, "unknown format of level file '%s'", filename);
336 else /* check for pre-2.0 file format with cookie string */
338 strcpy(cookie, chunk_name);
339 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
340 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
341 cookie[strlen(cookie) - 1] = '\0';
343 if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
345 Error(ERR_WARN, "unknown format of level file '%s'", filename);
350 if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
352 Error(ERR_WARN, "unsupported version of level file '%s'", filename);
357 /* pre-2.0 level files have no game version, so use file version here */
358 level.game_version = level.file_version;
361 if (level.file_version < FILE_VERSION_1_2)
363 /* level files from versions before 1.2.0 without chunk structure */
364 LoadLevel_HEAD(file, LEVEL_HEADER_SIZE, &level);
365 LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
373 int (*loader)(FILE *, int, struct LevelInfo *);
377 { "VERS", FILE_VERS_CHUNK_SIZE, LoadLevel_VERS },
378 { "HEAD", LEVEL_HEADER_SIZE, LoadLevel_HEAD },
379 { "AUTH", MAX_LEVEL_AUTHOR_LEN, LoadLevel_AUTH },
380 { "CONT", -1, LoadLevel_CONT },
381 { "BODY", -1, LoadLevel_BODY },
382 { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
386 while (getFileChunkBE(file, chunk_name, &chunk_size))
390 while (chunk_info[i].name != NULL &&
391 strcmp(chunk_name, chunk_info[i].name) != 0)
394 if (chunk_info[i].name == NULL)
396 Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
397 chunk_name, filename);
398 ReadUnusedBytesFromFile(file, chunk_size);
400 else if (chunk_info[i].size != -1 &&
401 chunk_info[i].size != chunk_size)
403 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
404 chunk_size, chunk_name, filename);
405 ReadUnusedBytesFromFile(file, chunk_size);
409 /* call function to load this level chunk */
410 int chunk_size_expected =
411 (chunk_info[i].loader)(file, chunk_size, &level);
413 /* the size of some chunks cannot be checked before reading other
414 chunks first (like "HEAD" and "BODY") that contain some header
415 information, so check them here */
416 if (chunk_size_expected != chunk_size)
418 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
419 chunk_size, chunk_name, filename);
427 if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
428 IS_LEVELCLASS_USER(leveldir_current))
430 /* For user contributed and private levels, use the version of
431 the game engine the levels were created for.
432 Since 2.0.1, the game engine version is now directly stored
433 in the level file (chunk "VERS"), so there is no need anymore
434 to set the game version from the file version (except for old,
435 pre-2.0 levels, where the game version is still taken from the
436 file format version used to store the level -- see above). */
438 /* do some special adjustments to support older level versions */
439 if (level.file_version == FILE_VERSION_1_0)
441 Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
442 Error(ERR_WARN, "using high speed movement for player");
444 /* player was faster than monsters in (pre-)1.0 levels */
445 level.double_speed = TRUE;
448 /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
449 if (level.game_version == VERSION_IDENT(2,0,1))
450 level.em_slippery_gems = TRUE;
454 /* Always use the latest version of the game engine for all but
455 user contributed and private levels; this allows for actual
456 corrections in the game engine to take effect for existing,
457 converted levels (from "classic" or other existing games) to
458 make the game emulation more accurate, while (hopefully) not
459 breaking existing levels created from other players. */
461 level.game_version = GAME_VERSION_ACTUAL;
463 /* Set special EM style gems behaviour: EM style gems slip down from
464 normal, steel and growing wall. As this is a more fundamental change,
465 it seems better to set the default behaviour to "off" (as it is more
466 natural) and make it configurable in the level editor (as a property
467 of gem style elements). Already existing converted levels (neither
468 private nor contributed levels) are changed to the new behaviour. */
470 if (level.file_version < FILE_VERSION_2_0)
471 level.em_slippery_gems = TRUE;
474 /* determine border element for this level */
478 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
482 fputc(level->fieldx, file);
483 fputc(level->fieldy, file);
485 putFile16BitBE(file, level->time);
486 putFile16BitBE(file, level->gems_needed);
488 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
489 fputc(level->name[i], file);
491 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
492 fputc(level->score[i], file);
494 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
497 fputc((level->encoding_16bit_yamyam ? EL_LEERRAUM :
498 level->yam_content[i][x][y]),
500 fputc(level->amoeba_speed, file);
501 fputc(level->time_magic_wall, file);
502 fputc(level->time_wheel, file);
503 fputc((level->encoding_16bit_amoeba ? EL_LEERRAUM : level->amoeba_content),
505 fputc((level->double_speed ? 1 : 0), file);
506 fputc((level->gravity ? 1 : 0), file);
507 fputc((level->encoding_16bit_field ? 1 : 0), file);
508 fputc((level->em_slippery_gems ? 1 : 0), file);
510 WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
513 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
517 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
518 fputc(level->author[i], file);
522 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
526 fputc(EL_MAMPFER, file);
527 fputc(level->num_yam_contents, file);
531 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
534 if (level->encoding_16bit_field)
535 putFile16BitBE(file, level->yam_content[i][x][y]);
537 fputc(level->yam_content[i][x][y], file);
541 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
545 for(y=0; y<level->fieldy; y++)
546 for(x=0; x<level->fieldx; x++)
547 if (level->encoding_16bit_field)
548 putFile16BitBE(file, Ur[x][y]);
550 fputc(Ur[x][y], file);
553 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
556 int num_contents, content_xsize, content_ysize;
557 int content_array[MAX_ELEMENT_CONTENTS][3][3];
559 if (element == EL_MAMPFER)
561 num_contents = level->num_yam_contents;
565 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
568 content_array[i][x][y] = level->yam_content[i][x][y];
570 else if (element == EL_AMOEBE_BD)
576 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
579 content_array[i][x][y] = EL_LEERRAUM;
580 content_array[0][0][0] = level->amoeba_content;
584 /* chunk header already written -- write empty chunk data */
585 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
587 Error(ERR_WARN, "cannot save content for element '%d'", element);
591 putFile16BitBE(file, element);
592 fputc(num_contents, file);
593 fputc(content_xsize, file);
594 fputc(content_ysize, file);
596 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
598 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
601 putFile16BitBE(file, content_array[i][x][y]);
604 void SaveLevel(int level_nr)
607 char *filename = getLevelFilename(level_nr);
611 if (!(file = fopen(filename, MODE_WRITE)))
613 Error(ERR_WARN, "cannot save level file '%s'", filename);
618 /* check level field for 16-bit elements */
619 level.encoding_16bit_field = FALSE;
620 for(y=0; y<level.fieldy; y++)
621 for(x=0; x<level.fieldx; x++)
623 level.encoding_16bit_field = TRUE;
625 /* check yamyam content for 16-bit elements */
626 level.encoding_16bit_yamyam = FALSE;
627 for(i=0; i<level.num_yam_contents; i++)
630 if (level.yam_content[i][x][y] > 255)
631 level.encoding_16bit_yamyam = TRUE;
633 /* check amoeba content for 16-bit elements */
634 level.encoding_16bit_amoeba = FALSE;
635 if (level.amoeba_content > 255)
636 level.encoding_16bit_amoeba = TRUE;
639 level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
641 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
642 putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
644 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
645 WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
647 putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
648 SaveLevel_HEAD(file, &level);
650 putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
651 SaveLevel_AUTH(file, &level);
653 putFileChunkBE(file, "BODY", body_chunk_size);
654 SaveLevel_BODY(file, &level);
656 if (level.encoding_16bit_yamyam ||
657 level.num_yam_contents != STD_ELEMENT_CONTENTS)
659 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
660 SaveLevel_CNT2(file, &level, EL_MAMPFER);
663 if (level.encoding_16bit_amoeba)
665 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
666 SaveLevel_CNT2(file, &level, EL_AMOEBE_BD);
671 SetFilePermissions(filename, PERMS_PRIVATE);
675 /* ========================================================================= */
676 /* tape file functions */
677 /* ========================================================================= */
679 static void setTapeInfoToDefaults()
683 /* always start with reliable default values (empty tape) */
684 tape.file_version = FILE_VERSION_ACTUAL;
685 tape.game_version = GAME_VERSION_ACTUAL;
688 /* default values (also for pre-1.2 tapes) with only the first player */
689 tape.player_participates[0] = TRUE;
690 for(i=1; i<MAX_PLAYERS; i++)
691 tape.player_participates[i] = FALSE;
693 /* at least one (default: the first) player participates in every tape */
694 tape.num_participating_players = 1;
696 tape.level_nr = level_nr;
698 tape.changed = FALSE;
700 tape.recording = FALSE;
701 tape.playing = FALSE;
702 tape.pausing = FALSE;
705 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
707 ReadChunk_VERS(file, &(tape->file_version), &(tape->game_version));
712 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
716 tape->random_seed = getFile32BitBE(file);
717 tape->date = getFile32BitBE(file);
718 tape->length = getFile32BitBE(file);
720 /* read header fields that are new since version 1.2 */
721 if (tape->file_version >= FILE_VERSION_1_2)
723 byte store_participating_players = fgetc(file);
725 ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
727 /* since version 1.2, tapes store which players participate in the tape */
728 tape->num_participating_players = 0;
729 for(i=0; i<MAX_PLAYERS; i++)
731 tape->player_participates[i] = FALSE;
733 if (store_participating_players & (1 << i))
735 tape->player_participates[i] = TRUE;
736 tape->num_participating_players++;
744 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
747 int chunk_size_expected =
748 (tape->num_participating_players + 1) * tape->length;
750 if (chunk_size_expected != chunk_size)
752 ReadUnusedBytesFromFile(file, chunk_size);
753 return chunk_size_expected;
756 for(i=0; i<tape->length; i++)
758 if (i >= MAX_TAPELEN)
761 for(j=0; j<MAX_PLAYERS; j++)
763 tape->pos[i].action[j] = MV_NO_MOVING;
765 if (tape->player_participates[j])
766 tape->pos[i].action[j] = fgetc(file);
769 tape->pos[i].delay = fgetc(file);
771 if (tape->file_version == FILE_VERSION_1_0)
773 /* eliminate possible diagonal moves in old tapes */
774 /* this is only for backward compatibility */
776 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
777 byte action = tape->pos[i].action[0];
778 int k, num_moves = 0;
782 if (action & joy_dir[k])
784 tape->pos[i + num_moves].action[0] = joy_dir[k];
786 tape->pos[i + num_moves].delay = 0;
795 tape->length += num_moves;
798 else if (tape->file_version < FILE_VERSION_2_0)
800 /* convert pre-2.0 tapes to new tape format */
802 if (tape->pos[i].delay > 1)
805 tape->pos[i + 1] = tape->pos[i];
806 tape->pos[i + 1].delay = 1;
809 for(j=0; j<MAX_PLAYERS; j++)
810 tape->pos[i].action[j] = MV_NO_MOVING;
811 tape->pos[i].delay--;
822 if (i != tape->length)
823 chunk_size = (tape->num_participating_players + 1) * i;
828 void LoadTape(int level_nr)
830 char *filename = getTapeFilename(level_nr);
831 char cookie[MAX_LINE_LEN];
832 char chunk_name[CHUNK_ID_LEN + 1];
836 /* always start with reliable default values */
837 setTapeInfoToDefaults();
839 if (!(file = fopen(filename, MODE_READ)))
842 getFileChunkBE(file, chunk_name, NULL);
843 if (strcmp(chunk_name, "RND1") == 0)
845 getFile32BitBE(file); /* not used */
847 getFileChunkBE(file, chunk_name, NULL);
848 if (strcmp(chunk_name, "TAPE") != 0)
850 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
855 else /* check for pre-2.0 file format with cookie string */
857 strcpy(cookie, chunk_name);
858 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
859 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
860 cookie[strlen(cookie) - 1] = '\0';
862 if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
864 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
869 if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
871 Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
876 /* pre-2.0 tape files have no game version, so use file version here */
877 tape.game_version = tape.file_version;
880 if (tape.file_version < FILE_VERSION_1_2)
882 /* tape files from versions before 1.2.0 without chunk structure */
883 LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
884 LoadTape_BODY(file, 2 * tape.length, &tape);
892 int (*loader)(FILE *, int, struct TapeInfo *);
896 { "VERS", FILE_VERS_CHUNK_SIZE, LoadTape_VERS },
897 { "HEAD", TAPE_HEADER_SIZE, LoadTape_HEAD },
898 { "BODY", -1, LoadTape_BODY },
902 while (getFileChunkBE(file, chunk_name, &chunk_size))
906 while (chunk_info[i].name != NULL &&
907 strcmp(chunk_name, chunk_info[i].name) != 0)
910 if (chunk_info[i].name == NULL)
912 Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
913 chunk_name, filename);
914 ReadUnusedBytesFromFile(file, chunk_size);
916 else if (chunk_info[i].size != -1 &&
917 chunk_info[i].size != chunk_size)
919 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
920 chunk_size, chunk_name, filename);
921 ReadUnusedBytesFromFile(file, chunk_size);
925 /* call function to load this tape chunk */
926 int chunk_size_expected =
927 (chunk_info[i].loader)(file, chunk_size, &tape);
929 /* the size of some chunks cannot be checked before reading other
930 chunks first (like "HEAD" and "BODY") that contain some header
931 information, so check them here */
932 if (chunk_size_expected != chunk_size)
934 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
935 chunk_size, chunk_name, filename);
943 tape.length_seconds = GetTapeLength();
946 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
949 byte store_participating_players = 0;
951 /* set bits for participating players for compact storage */
952 for(i=0; i<MAX_PLAYERS; i++)
953 if (tape->player_participates[i])
954 store_participating_players |= (1 << i);
956 putFile32BitBE(file, tape->random_seed);
957 putFile32BitBE(file, tape->date);
958 putFile32BitBE(file, tape->length);
960 fputc(store_participating_players, file);
962 WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
965 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
969 for(i=0; i<tape->length; i++)
971 for(j=0; j<MAX_PLAYERS; j++)
972 if (tape->player_participates[j])
973 fputc(tape->pos[i].action[j], file);
975 fputc(tape->pos[i].delay, file);
979 void SaveTape(int level_nr)
982 char *filename = getTapeFilename(level_nr);
984 boolean new_tape = TRUE;
985 int num_participating_players = 0;
988 InitTapeDirectory(leveldir_current->filename);
990 /* if a tape still exists, ask to overwrite it */
991 if (access(filename, F_OK) == 0)
994 if (!Request("Replace old tape ?", REQ_ASK))
998 if (!(file = fopen(filename, MODE_WRITE)))
1000 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
1004 /* count number of participating players */
1005 for(i=0; i<MAX_PLAYERS; i++)
1006 if (tape.player_participates[i])
1007 num_participating_players++;
1009 body_chunk_size = (num_participating_players + 1) * tape.length;
1011 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1012 putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
1014 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1015 WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
1017 putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
1018 SaveTape_HEAD(file, &tape);
1020 putFileChunkBE(file, "BODY", body_chunk_size);
1021 SaveTape_BODY(file, &tape);
1025 SetFilePermissions(filename, PERMS_PRIVATE);
1027 tape.changed = FALSE;
1030 Request("tape saved !", REQ_CONFIRM);
1033 void DumpTape(struct TapeInfo *tape)
1037 if (TAPE_IS_EMPTY(*tape))
1039 Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
1044 printf("-------------------------------------------------------------------------------\n");
1045 printf("Tape of Level %d (file version %06d, game version %06d\n",
1046 tape->level_nr, tape->file_version, tape->game_version);
1047 printf("-------------------------------------------------------------------------------\n");
1049 for(i=0; i<tape->length; i++)
1051 if (i >= MAX_TAPELEN)
1054 for(j=0; j<MAX_PLAYERS; j++)
1056 if (tape->player_participates[j])
1058 int action = tape->pos[i].action[j];
1060 printf("%d:%02x ", j, action);
1061 printf("[%c%c%c%c|%c%c] - ",
1062 (action & JOY_LEFT ? '<' : ' '),
1063 (action & JOY_RIGHT ? '>' : ' '),
1064 (action & JOY_UP ? '^' : ' '),
1065 (action & JOY_DOWN ? 'v' : ' '),
1066 (action & JOY_BUTTON_1 ? '1' : ' '),
1067 (action & JOY_BUTTON_2 ? '2' : ' '));
1071 printf("(%03d)\n", tape->pos[i].delay);
1074 printf("-------------------------------------------------------------------------------\n");
1078 /* ========================================================================= */
1079 /* score file functions */
1080 /* ========================================================================= */
1082 void LoadScore(int level_nr)
1085 char *filename = getScoreFilename(level_nr);
1086 char cookie[MAX_LINE_LEN];
1087 char line[MAX_LINE_LEN];
1091 /* always start with reliable default values */
1092 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1094 strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
1095 highscore[i].Score = 0;
1098 if (!(file = fopen(filename, MODE_READ)))
1101 /* check file identifier */
1102 fgets(cookie, MAX_LINE_LEN, file);
1103 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1104 cookie[strlen(cookie) - 1] = '\0';
1106 if (!checkCookieString(cookie, SCORE_COOKIE))
1108 Error(ERR_WARN, "unknown format of score file '%s'", filename);
1113 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1115 fscanf(file, "%d", &highscore[i].Score);
1116 fgets(line, MAX_LINE_LEN, file);
1118 if (line[strlen(line) - 1] == '\n')
1119 line[strlen(line) - 1] = '\0';
1121 for (line_ptr = line; *line_ptr; line_ptr++)
1123 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
1125 strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
1126 highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
1135 void SaveScore(int level_nr)
1138 char *filename = getScoreFilename(level_nr);
1141 InitScoreDirectory(leveldir_current->filename);
1143 if (!(file = fopen(filename, MODE_WRITE)))
1145 Error(ERR_WARN, "cannot save score for level %d", level_nr);
1149 fprintf(file, "%s\n\n", SCORE_COOKIE);
1151 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1152 fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
1156 SetFilePermissions(filename, PERMS_PUBLIC);
1160 /* ========================================================================= */
1161 /* setup file functions */
1162 /* ========================================================================= */
1164 #define TOKEN_STR_PLAYER_PREFIX "player_"
1167 #define SETUP_TOKEN_PLAYER_NAME 0
1168 #define SETUP_TOKEN_SOUND 1
1169 #define SETUP_TOKEN_SOUND_LOOPS 2
1170 #define SETUP_TOKEN_SOUND_MUSIC 3
1171 #define SETUP_TOKEN_SOUND_SIMPLE 4
1172 #define SETUP_TOKEN_TOONS 5
1173 #define SETUP_TOKEN_SCROLL_DELAY 6
1174 #define SETUP_TOKEN_SOFT_SCROLLING 7
1175 #define SETUP_TOKEN_FADING 8
1176 #define SETUP_TOKEN_AUTORECORD 9
1177 #define SETUP_TOKEN_QUICK_DOORS 10
1178 #define SETUP_TOKEN_TEAM_MODE 11
1179 #define SETUP_TOKEN_HANDICAP 12
1180 #define SETUP_TOKEN_TIME_LIMIT 13
1181 #define SETUP_TOKEN_FULLSCREEN 14
1182 #define SETUP_TOKEN_ASK_ON_ESCAPE 15
1183 #define SETUP_TOKEN_GRAPHICS_SET 16
1184 #define SETUP_TOKEN_SOUNDS_SET 17
1185 #define SETUP_TOKEN_MUSIC_SET 18
1186 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 19
1187 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 20
1188 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 21
1190 #define NUM_GLOBAL_SETUP_TOKENS 22
1192 /* shortcut setup */
1193 #define SETUP_TOKEN_SAVE_GAME 0
1194 #define SETUP_TOKEN_LOAD_GAME 1
1195 #define SETUP_TOKEN_TOGGLE_PAUSE 2
1197 #define NUM_SHORTCUT_SETUP_TOKENS 3
1200 #define SETUP_TOKEN_USE_JOYSTICK 0
1201 #define SETUP_TOKEN_JOY_DEVICE_NAME 1
1202 #define SETUP_TOKEN_JOY_XLEFT 2
1203 #define SETUP_TOKEN_JOY_XMIDDLE 3
1204 #define SETUP_TOKEN_JOY_XRIGHT 4
1205 #define SETUP_TOKEN_JOY_YUPPER 5
1206 #define SETUP_TOKEN_JOY_YMIDDLE 6
1207 #define SETUP_TOKEN_JOY_YLOWER 7
1208 #define SETUP_TOKEN_JOY_SNAP 8
1209 #define SETUP_TOKEN_JOY_BOMB 9
1210 #define SETUP_TOKEN_KEY_LEFT 10
1211 #define SETUP_TOKEN_KEY_RIGHT 11
1212 #define SETUP_TOKEN_KEY_UP 12
1213 #define SETUP_TOKEN_KEY_DOWN 13
1214 #define SETUP_TOKEN_KEY_SNAP 14
1215 #define SETUP_TOKEN_KEY_BOMB 15
1217 #define NUM_PLAYER_SETUP_TOKENS 16
1219 static struct SetupInfo si;
1220 static struct SetupShortcutInfo ssi;
1221 static struct SetupInputInfo sii;
1223 static struct TokenInfo global_setup_tokens[] =
1226 { TYPE_STRING, &si.player_name, "player_name" },
1227 { TYPE_SWITCH, &si.sound, "sound" },
1228 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
1229 { TYPE_SWITCH, &si.sound_music, "background_music" },
1230 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
1231 { TYPE_SWITCH, &si.toons, "toons" },
1232 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
1233 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
1234 { TYPE_SWITCH, &si.fading, "screen_fading" },
1235 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
1236 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
1237 { TYPE_SWITCH, &si.team_mode, "team_mode" },
1238 { TYPE_SWITCH, &si.handicap, "handicap" },
1239 { TYPE_SWITCH, &si.time_limit, "time_limit" },
1240 { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
1241 { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
1242 { TYPE_STRING, &si.graphics_set, "graphics_set" },
1243 { TYPE_STRING, &si.sounds_set, "sounds_set" },
1244 { TYPE_STRING, &si.music_set, "music_set" },
1245 { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
1246 { TYPE_SWITCH, &si.override_level_sounds, "override_level_sounds" },
1247 { TYPE_SWITCH, &si.override_level_music, "override_level_music" },
1250 static struct TokenInfo shortcut_setup_tokens[] =
1252 /* shortcut setup */
1253 { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
1254 { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
1255 { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }
1258 static struct TokenInfo player_setup_tokens[] =
1261 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
1262 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
1263 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
1264 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
1265 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
1266 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
1267 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
1268 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
1269 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
1270 { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
1271 { TYPE_KEY_X11, &sii.key.left, ".key.move_left" },
1272 { TYPE_KEY_X11, &sii.key.right, ".key.move_right" },
1273 { TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
1274 { TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
1275 { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
1276 { TYPE_KEY_X11, &sii.key.bomb, ".key.place_bomb" }
1279 static void setSetupInfoToDefaults(struct SetupInfo *si)
1283 si->player_name = getStringCopy(getLoginName());
1286 si->sound_loops = TRUE;
1287 si->sound_music = TRUE;
1288 si->sound_simple = TRUE;
1290 si->double_buffering = TRUE;
1291 si->direct_draw = !si->double_buffering;
1292 si->scroll_delay = TRUE;
1293 si->soft_scrolling = TRUE;
1295 si->autorecord = TRUE;
1296 si->quick_doors = FALSE;
1297 si->team_mode = FALSE;
1298 si->handicap = TRUE;
1299 si->time_limit = TRUE;
1300 si->fullscreen = FALSE;
1301 si->ask_on_escape = TRUE;
1303 si->graphics_set = getStringCopy(GRAPHICS_SUBDIR);
1304 si->sounds_set = getStringCopy(SOUNDS_SUBDIR);
1305 si->music_set = getStringCopy(MUSIC_SUBDIR);
1306 si->override_level_graphics = FALSE;
1307 si->override_level_sounds = FALSE;
1308 si->override_level_music = FALSE;
1310 si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
1311 si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
1312 si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
1314 for (i=0; i<MAX_PLAYERS; i++)
1316 si->input[i].use_joystick = FALSE;
1317 si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
1318 si->input[i].joy.xleft = JOYSTICK_XLEFT;
1319 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1320 si->input[i].joy.xright = JOYSTICK_XRIGHT;
1321 si->input[i].joy.yupper = JOYSTICK_YUPPER;
1322 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1323 si->input[i].joy.ylower = JOYSTICK_YLOWER;
1324 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
1325 si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
1326 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
1327 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
1328 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
1329 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
1330 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
1331 si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED);
1335 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
1339 if (!setup_file_list)
1344 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1345 setSetupInfo(global_setup_tokens, i,
1346 getTokenValue(setup_file_list, global_setup_tokens[i].text));
1349 /* shortcut setup */
1350 ssi = setup.shortcut;
1351 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1352 setSetupInfo(shortcut_setup_tokens, i,
1353 getTokenValue(setup_file_list,shortcut_setup_tokens[i].text));
1354 setup.shortcut = ssi;
1357 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1361 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1363 sii = setup.input[pnr];
1364 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1366 char full_token[100];
1368 sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
1369 setSetupInfo(player_setup_tokens, i,
1370 getTokenValue(setup_file_list, full_token));
1372 setup.input[pnr] = sii;
1378 char *filename = getSetupFilename();
1379 struct SetupFileList *setup_file_list = NULL;
1381 /* always start with reliable default values */
1382 setSetupInfoToDefaults(&setup);
1384 setup_file_list = loadSetupFileList(filename);
1386 if (setup_file_list)
1388 checkSetupFileListIdentifier(setup_file_list, getCookie("SETUP"));
1389 decodeSetupFileList(setup_file_list);
1391 setup.direct_draw = !setup.double_buffering;
1393 freeSetupFileList(setup_file_list);
1395 /* needed to work around problems with fixed length strings */
1396 if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN)
1397 setup.player_name[MAX_PLAYER_NAME_LEN] = '\0';
1398 else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN)
1400 char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
1402 strcpy(new_name, setup.player_name);
1403 free(setup.player_name);
1404 setup.player_name = new_name;
1408 Error(ERR_WARN, "using default setup values");
1413 char *filename = getSetupFilename();
1417 InitUserDataDirectory();
1419 if (!(file = fopen(filename, MODE_WRITE)))
1421 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1425 fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
1426 getCookie("SETUP")));
1427 fprintf(file, "\n");
1431 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1433 fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
1435 /* just to make things nicer :) */
1436 if (i == SETUP_TOKEN_PLAYER_NAME || i == SETUP_TOKEN_GRAPHICS_SET - 1)
1437 fprintf(file, "\n");
1440 /* shortcut setup */
1441 ssi = setup.shortcut;
1442 fprintf(file, "\n");
1443 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1444 fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
1447 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1451 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1452 fprintf(file, "\n");
1454 sii = setup.input[pnr];
1455 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1456 fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
1461 SetFilePermissions(filename, PERMS_PRIVATE);