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;
450 /* Always use the latest version of the game engine for all but
451 user contributed and private levels; this allows for actual
452 corrections in the game engine to take effect for existing,
453 converted levels (from "classic" or other existing games) to
454 make the game emulation more accurate, while (hopefully) not
455 breaking existing levels created from other players. */
457 level.game_version = GAME_VERSION_ACTUAL;
459 /* Set special EM style gems behaviour: EM style gems slip down from
460 normal, steel and growing wall. As this is a more fundamental change,
461 it seems better to set the default behaviour to "off" (as it is more
462 natural) and make it configurable in the level editor (as a property
463 of gem style elements). Already existing converted levels (neither
464 private nor contributed levels) are changed to the new behaviour. */
466 if (level.file_version < FILE_VERSION_2_0)
467 level.em_slippery_gems = TRUE;
470 /* determine border element for this level */
474 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
478 fputc(level->fieldx, file);
479 fputc(level->fieldy, file);
481 putFile16BitBE(file, level->time);
482 putFile16BitBE(file, level->gems_needed);
484 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
485 fputc(level->name[i], file);
487 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
488 fputc(level->score[i], file);
490 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
493 fputc((level->encoding_16bit_yamyam ? EL_LEERRAUM :
494 level->yam_content[i][x][y]),
496 fputc(level->amoeba_speed, file);
497 fputc(level->time_magic_wall, file);
498 fputc(level->time_wheel, file);
499 fputc((level->encoding_16bit_amoeba ? EL_LEERRAUM : level->amoeba_content),
501 fputc((level->double_speed ? 1 : 0), file);
502 fputc((level->gravity ? 1 : 0), file);
503 fputc((level->encoding_16bit_field ? 1 : 0), file);
504 fputc((level->em_slippery_gems ? 1 : 0), file);
506 WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
509 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
513 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
514 fputc(level->author[i], file);
518 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
522 fputc(EL_MAMPFER, file);
523 fputc(level->num_yam_contents, file);
527 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
530 if (level->encoding_16bit_field)
531 putFile16BitBE(file, level->yam_content[i][x][y]);
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 putFile16BitBE(file, Ur[x][y]);
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 putFile16BitBE(file, element);
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 putFile16BitBE(file, content_array[i][x][y]);
600 void SaveLevel(int level_nr)
603 char *filename = getLevelFilename(level_nr);
607 if (!(file = fopen(filename, MODE_WRITE)))
609 Error(ERR_WARN, "cannot save level file '%s'", filename);
614 /* check level field for 16-bit elements */
615 level.encoding_16bit_field = FALSE;
616 for(y=0; y<level.fieldy; y++)
617 for(x=0; x<level.fieldx; x++)
619 level.encoding_16bit_field = TRUE;
621 /* check yamyam content for 16-bit elements */
622 level.encoding_16bit_yamyam = FALSE;
623 for(i=0; i<level.num_yam_contents; i++)
626 if (level.yam_content[i][x][y] > 255)
627 level.encoding_16bit_yamyam = TRUE;
629 /* check amoeba content for 16-bit elements */
630 level.encoding_16bit_amoeba = FALSE;
631 if (level.amoeba_content > 255)
632 level.encoding_16bit_amoeba = TRUE;
635 level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
637 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
638 putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
640 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
641 WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
643 putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
644 SaveLevel_HEAD(file, &level);
646 putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
647 SaveLevel_AUTH(file, &level);
649 putFileChunkBE(file, "BODY", body_chunk_size);
650 SaveLevel_BODY(file, &level);
652 if (level.encoding_16bit_yamyam ||
653 level.num_yam_contents != STD_ELEMENT_CONTENTS)
655 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
656 SaveLevel_CNT2(file, &level, EL_MAMPFER);
659 if (level.encoding_16bit_amoeba)
661 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
662 SaveLevel_CNT2(file, &level, EL_AMOEBE_BD);
667 SetFilePermissions(filename, PERMS_PRIVATE);
671 /* ========================================================================= */
672 /* tape file functions */
673 /* ========================================================================= */
675 static void setTapeInfoToDefaults()
679 /* always start with reliable default values (empty tape) */
680 tape.file_version = FILE_VERSION_ACTUAL;
681 tape.game_version = GAME_VERSION_ACTUAL;
684 /* default values (also for pre-1.2 tapes) with only the first player */
685 tape.player_participates[0] = TRUE;
686 for(i=1; i<MAX_PLAYERS; i++)
687 tape.player_participates[i] = FALSE;
689 /* at least one (default: the first) player participates in every tape */
690 tape.num_participating_players = 1;
692 tape.level_nr = level_nr;
694 tape.changed = FALSE;
696 tape.recording = FALSE;
697 tape.playing = FALSE;
698 tape.pausing = FALSE;
701 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
703 ReadChunk_VERS(file, &(tape->file_version), &(tape->game_version));
708 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
712 tape->random_seed = getFile32BitBE(file);
713 tape->date = getFile32BitBE(file);
714 tape->length = getFile32BitBE(file);
716 /* read header fields that are new since version 1.2 */
717 if (tape->file_version >= FILE_VERSION_1_2)
719 byte store_participating_players = fgetc(file);
721 ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
723 /* since version 1.2, tapes store which players participate in the tape */
724 tape->num_participating_players = 0;
725 for(i=0; i<MAX_PLAYERS; i++)
727 tape->player_participates[i] = FALSE;
729 if (store_participating_players & (1 << i))
731 tape->player_participates[i] = TRUE;
732 tape->num_participating_players++;
740 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
743 int chunk_size_expected =
744 (tape->num_participating_players + 1) * tape->length;
746 if (chunk_size_expected != chunk_size)
748 ReadUnusedBytesFromFile(file, chunk_size);
749 return chunk_size_expected;
752 for(i=0; i<tape->length; i++)
754 if (i >= MAX_TAPELEN)
757 for(j=0; j<MAX_PLAYERS; j++)
759 tape->pos[i].action[j] = MV_NO_MOVING;
761 if (tape->player_participates[j])
762 tape->pos[i].action[j] = fgetc(file);
765 tape->pos[i].delay = fgetc(file);
767 if (tape->file_version == FILE_VERSION_1_0)
769 /* eliminate possible diagonal moves in old tapes */
770 /* this is only for backward compatibility */
772 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
773 byte action = tape->pos[i].action[0];
774 int k, num_moves = 0;
778 if (action & joy_dir[k])
780 tape->pos[i + num_moves].action[0] = joy_dir[k];
782 tape->pos[i + num_moves].delay = 0;
791 tape->length += num_moves;
794 else if (tape->file_version < FILE_VERSION_2_0)
796 /* convert pre-2.0 tapes to new tape format */
798 if (tape->pos[i].delay > 1)
801 tape->pos[i + 1] = tape->pos[i];
802 tape->pos[i + 1].delay = 1;
805 for(j=0; j<MAX_PLAYERS; j++)
806 tape->pos[i].action[j] = MV_NO_MOVING;
807 tape->pos[i].delay--;
818 if (i != tape->length)
819 chunk_size = (tape->num_participating_players + 1) * i;
824 void LoadTape(int level_nr)
826 char *filename = getTapeFilename(level_nr);
827 char cookie[MAX_LINE_LEN];
828 char chunk_name[CHUNK_ID_LEN + 1];
832 /* always start with reliable default values */
833 setTapeInfoToDefaults();
835 if (!(file = fopen(filename, MODE_READ)))
838 getFileChunkBE(file, chunk_name, NULL);
839 if (strcmp(chunk_name, "RND1") == 0)
841 getFile32BitBE(file); /* not used */
843 getFileChunkBE(file, chunk_name, NULL);
844 if (strcmp(chunk_name, "TAPE") != 0)
846 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
851 else /* check for pre-2.0 file format with cookie string */
853 strcpy(cookie, chunk_name);
854 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
855 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
856 cookie[strlen(cookie) - 1] = '\0';
858 if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
860 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
865 if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
867 Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
872 /* pre-2.0 tape files have no game version, so use file version here */
873 tape.game_version = tape.file_version;
876 if (tape.file_version < FILE_VERSION_1_2)
878 /* tape files from versions before 1.2.0 without chunk structure */
879 LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
880 LoadTape_BODY(file, 2 * tape.length, &tape);
888 int (*loader)(FILE *, int, struct TapeInfo *);
892 { "VERS", FILE_VERS_CHUNK_SIZE, LoadTape_VERS },
893 { "HEAD", TAPE_HEADER_SIZE, LoadTape_HEAD },
894 { "BODY", -1, LoadTape_BODY },
898 while (getFileChunkBE(file, chunk_name, &chunk_size))
902 while (chunk_info[i].name != NULL &&
903 strcmp(chunk_name, chunk_info[i].name) != 0)
906 if (chunk_info[i].name == NULL)
908 Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
909 chunk_name, filename);
910 ReadUnusedBytesFromFile(file, chunk_size);
912 else if (chunk_info[i].size != -1 &&
913 chunk_info[i].size != chunk_size)
915 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
916 chunk_size, chunk_name, filename);
917 ReadUnusedBytesFromFile(file, chunk_size);
921 /* call function to load this tape chunk */
922 int chunk_size_expected =
923 (chunk_info[i].loader)(file, chunk_size, &tape);
925 /* the size of some chunks cannot be checked before reading other
926 chunks first (like "HEAD" and "BODY") that contain some header
927 information, so check them here */
928 if (chunk_size_expected != chunk_size)
930 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
931 chunk_size, chunk_name, filename);
939 tape.length_seconds = GetTapeLength();
942 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
945 byte store_participating_players = 0;
947 /* set bits for participating players for compact storage */
948 for(i=0; i<MAX_PLAYERS; i++)
949 if (tape->player_participates[i])
950 store_participating_players |= (1 << i);
952 putFile32BitBE(file, tape->random_seed);
953 putFile32BitBE(file, tape->date);
954 putFile32BitBE(file, tape->length);
956 fputc(store_participating_players, file);
958 WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
961 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
965 for(i=0; i<tape->length; i++)
967 for(j=0; j<MAX_PLAYERS; j++)
968 if (tape->player_participates[j])
969 fputc(tape->pos[i].action[j], file);
971 fputc(tape->pos[i].delay, file);
975 void SaveTape(int level_nr)
978 char *filename = getTapeFilename(level_nr);
980 boolean new_tape = TRUE;
981 int num_participating_players = 0;
984 InitTapeDirectory(leveldir_current->filename);
986 /* if a tape still exists, ask to overwrite it */
987 if (access(filename, F_OK) == 0)
990 if (!Request("Replace old tape ?", REQ_ASK))
994 if (!(file = fopen(filename, MODE_WRITE)))
996 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
1000 /* count number of participating players */
1001 for(i=0; i<MAX_PLAYERS; i++)
1002 if (tape.player_participates[i])
1003 num_participating_players++;
1005 body_chunk_size = (num_participating_players + 1) * tape.length;
1007 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1008 putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
1010 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1011 WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
1013 putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
1014 SaveTape_HEAD(file, &tape);
1016 putFileChunkBE(file, "BODY", body_chunk_size);
1017 SaveTape_BODY(file, &tape);
1021 SetFilePermissions(filename, PERMS_PRIVATE);
1023 tape.changed = FALSE;
1026 Request("tape saved !", REQ_CONFIRM);
1029 void DumpTape(struct TapeInfo *tape)
1033 if (TAPE_IS_EMPTY(*tape))
1035 Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
1040 printf("-------------------------------------------------------------------------------\n");
1041 printf("Tape of Level %d (file version %06d, game version %06d\n",
1042 tape->level_nr, tape->file_version, tape->game_version);
1043 printf("-------------------------------------------------------------------------------\n");
1045 for(i=0; i<tape->length; i++)
1047 if (i >= MAX_TAPELEN)
1050 for(j=0; j<MAX_PLAYERS; j++)
1052 if (tape->player_participates[j])
1054 int action = tape->pos[i].action[j];
1056 printf("%d:%02x ", j, action);
1057 printf("[%c%c%c%c|%c%c] - ",
1058 (action & JOY_LEFT ? '<' : ' '),
1059 (action & JOY_RIGHT ? '>' : ' '),
1060 (action & JOY_UP ? '^' : ' '),
1061 (action & JOY_DOWN ? 'v' : ' '),
1062 (action & JOY_BUTTON_1 ? '1' : ' '),
1063 (action & JOY_BUTTON_2 ? '2' : ' '));
1067 printf("(%03d)\n", tape->pos[i].delay);
1070 printf("-------------------------------------------------------------------------------\n");
1074 /* ========================================================================= */
1075 /* score file functions */
1076 /* ========================================================================= */
1078 void LoadScore(int level_nr)
1081 char *filename = getScoreFilename(level_nr);
1082 char cookie[MAX_LINE_LEN];
1083 char line[MAX_LINE_LEN];
1087 /* always start with reliable default values */
1088 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1090 strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
1091 highscore[i].Score = 0;
1094 if (!(file = fopen(filename, MODE_READ)))
1097 /* check file identifier */
1098 fgets(cookie, MAX_LINE_LEN, file);
1099 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1100 cookie[strlen(cookie) - 1] = '\0';
1102 if (!checkCookieString(cookie, SCORE_COOKIE))
1104 Error(ERR_WARN, "unknown format of score file '%s'", filename);
1109 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1111 fscanf(file, "%d", &highscore[i].Score);
1112 fgets(line, MAX_LINE_LEN, file);
1114 if (line[strlen(line) - 1] == '\n')
1115 line[strlen(line) - 1] = '\0';
1117 for (line_ptr = line; *line_ptr; line_ptr++)
1119 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
1121 strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
1122 highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
1131 void SaveScore(int level_nr)
1134 char *filename = getScoreFilename(level_nr);
1137 InitScoreDirectory(leveldir_current->filename);
1139 if (!(file = fopen(filename, MODE_WRITE)))
1141 Error(ERR_WARN, "cannot save score for level %d", level_nr);
1145 fprintf(file, "%s\n\n", SCORE_COOKIE);
1147 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1148 fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
1152 SetFilePermissions(filename, PERMS_PUBLIC);
1156 /* ========================================================================= */
1157 /* setup file functions */
1158 /* ========================================================================= */
1160 #define TOKEN_STR_PLAYER_PREFIX "player_"
1163 #define SETUP_TOKEN_PLAYER_NAME 0
1164 #define SETUP_TOKEN_SOUND 1
1165 #define SETUP_TOKEN_SOUND_LOOPS 2
1166 #define SETUP_TOKEN_SOUND_MUSIC 3
1167 #define SETUP_TOKEN_SOUND_SIMPLE 4
1168 #define SETUP_TOKEN_TOONS 5
1169 #define SETUP_TOKEN_SCROLL_DELAY 6
1170 #define SETUP_TOKEN_SOFT_SCROLLING 7
1171 #define SETUP_TOKEN_FADING 8
1172 #define SETUP_TOKEN_AUTORECORD 9
1173 #define SETUP_TOKEN_QUICK_DOORS 10
1174 #define SETUP_TOKEN_TEAM_MODE 11
1175 #define SETUP_TOKEN_HANDICAP 12
1176 #define SETUP_TOKEN_TIME_LIMIT 13
1177 #define SETUP_TOKEN_FULLSCREEN 14
1178 #define SETUP_TOKEN_ASK_ON_ESCAPE 15
1179 #define SETUP_TOKEN_GRAPHICS_SET 16
1180 #define SETUP_TOKEN_SOUNDS_SET 17
1181 #define SETUP_TOKEN_MUSIC_SET 18
1183 #define NUM_GLOBAL_SETUP_TOKENS 19
1185 /* shortcut setup */
1186 #define SETUP_TOKEN_SAVE_GAME 0
1187 #define SETUP_TOKEN_LOAD_GAME 1
1188 #define SETUP_TOKEN_TOGGLE_PAUSE 2
1190 #define NUM_SHORTCUT_SETUP_TOKENS 3
1193 #define SETUP_TOKEN_USE_JOYSTICK 0
1194 #define SETUP_TOKEN_JOY_DEVICE_NAME 1
1195 #define SETUP_TOKEN_JOY_XLEFT 2
1196 #define SETUP_TOKEN_JOY_XMIDDLE 3
1197 #define SETUP_TOKEN_JOY_XRIGHT 4
1198 #define SETUP_TOKEN_JOY_YUPPER 5
1199 #define SETUP_TOKEN_JOY_YMIDDLE 6
1200 #define SETUP_TOKEN_JOY_YLOWER 7
1201 #define SETUP_TOKEN_JOY_SNAP 8
1202 #define SETUP_TOKEN_JOY_BOMB 9
1203 #define SETUP_TOKEN_KEY_LEFT 10
1204 #define SETUP_TOKEN_KEY_RIGHT 11
1205 #define SETUP_TOKEN_KEY_UP 12
1206 #define SETUP_TOKEN_KEY_DOWN 13
1207 #define SETUP_TOKEN_KEY_SNAP 14
1208 #define SETUP_TOKEN_KEY_BOMB 15
1210 #define NUM_PLAYER_SETUP_TOKENS 16
1212 static struct SetupInfo si;
1213 static struct SetupShortcutInfo ssi;
1214 static struct SetupInputInfo sii;
1216 static struct TokenInfo global_setup_tokens[] =
1219 { TYPE_STRING, &si.player_name, "player_name" },
1220 { TYPE_SWITCH, &si.sound, "sound" },
1221 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
1222 { TYPE_SWITCH, &si.sound_music, "background_music" },
1223 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
1224 { TYPE_SWITCH, &si.toons, "toons" },
1225 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
1226 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
1227 { TYPE_SWITCH, &si.fading, "screen_fading" },
1228 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
1229 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
1230 { TYPE_SWITCH, &si.team_mode, "team_mode" },
1231 { TYPE_SWITCH, &si.handicap, "handicap" },
1232 { TYPE_SWITCH, &si.time_limit, "time_limit" },
1233 { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
1234 { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
1235 { TYPE_STRING, &si.graphics_set, "graphics_set" },
1236 { TYPE_STRING, &si.sounds_set, "sounds_set" },
1237 { TYPE_STRING, &si.music_set, "music_set" },
1240 static struct TokenInfo shortcut_setup_tokens[] =
1242 /* shortcut setup */
1243 { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
1244 { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
1245 { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }
1248 static struct TokenInfo player_setup_tokens[] =
1251 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
1252 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
1253 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
1254 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
1255 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
1256 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
1257 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
1258 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
1259 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
1260 { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
1261 { TYPE_KEY_X11, &sii.key.left, ".key.move_left" },
1262 { TYPE_KEY_X11, &sii.key.right, ".key.move_right" },
1263 { TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
1264 { TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
1265 { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
1266 { TYPE_KEY_X11, &sii.key.bomb, ".key.place_bomb" }
1269 static void setSetupInfoToDefaults(struct SetupInfo *si)
1273 si->player_name = getStringCopy(getLoginName());
1276 si->sound_loops = TRUE;
1277 si->sound_music = TRUE;
1278 si->sound_simple = TRUE;
1280 si->double_buffering = TRUE;
1281 si->direct_draw = !si->double_buffering;
1282 si->scroll_delay = TRUE;
1283 si->soft_scrolling = TRUE;
1285 si->autorecord = TRUE;
1286 si->quick_doors = FALSE;
1287 si->team_mode = FALSE;
1288 si->handicap = TRUE;
1289 si->time_limit = TRUE;
1290 si->fullscreen = FALSE;
1291 si->ask_on_escape = TRUE;
1293 si->graphics_set = getStringCopy(GRAPHICS_SUBDIR);
1294 si->sounds_set = getStringCopy(SOUNDS_SUBDIR);
1295 si->music_set = getStringCopy(MUSIC_SUBDIR);
1297 si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
1298 si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
1299 si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
1301 for (i=0; i<MAX_PLAYERS; i++)
1303 si->input[i].use_joystick = FALSE;
1304 si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
1305 si->input[i].joy.xleft = JOYSTICK_XLEFT;
1306 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1307 si->input[i].joy.xright = JOYSTICK_XRIGHT;
1308 si->input[i].joy.yupper = JOYSTICK_YUPPER;
1309 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1310 si->input[i].joy.ylower = JOYSTICK_YLOWER;
1311 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
1312 si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
1313 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
1314 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
1315 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
1316 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
1317 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
1318 si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED);
1322 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
1326 if (!setup_file_list)
1331 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1332 setSetupInfo(global_setup_tokens, i,
1333 getTokenValue(setup_file_list, global_setup_tokens[i].text));
1336 /* shortcut setup */
1337 ssi = setup.shortcut;
1338 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1339 setSetupInfo(shortcut_setup_tokens, i,
1340 getTokenValue(setup_file_list,shortcut_setup_tokens[i].text));
1341 setup.shortcut = ssi;
1344 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1348 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1350 sii = setup.input[pnr];
1351 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1353 char full_token[100];
1355 sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
1356 setSetupInfo(player_setup_tokens, i,
1357 getTokenValue(setup_file_list, full_token));
1359 setup.input[pnr] = sii;
1365 char *filename = getSetupFilename();
1366 struct SetupFileList *setup_file_list = NULL;
1368 /* always start with reliable default values */
1369 setSetupInfoToDefaults(&setup);
1371 setup_file_list = loadSetupFileList(filename);
1373 if (setup_file_list)
1375 checkSetupFileListIdentifier(setup_file_list, getCookie("SETUP"));
1376 decodeSetupFileList(setup_file_list);
1378 setup.direct_draw = !setup.double_buffering;
1380 freeSetupFileList(setup_file_list);
1382 /* needed to work around problems with fixed length strings */
1383 if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN)
1384 setup.player_name[MAX_PLAYER_NAME_LEN] = '\0';
1385 else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN)
1387 char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
1389 strcpy(new_name, setup.player_name);
1390 free(setup.player_name);
1391 setup.player_name = new_name;
1395 Error(ERR_WARN, "using default setup values");
1400 char *filename = getSetupFilename();
1404 InitUserDataDirectory();
1406 if (!(file = fopen(filename, MODE_WRITE)))
1408 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1412 fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
1413 getCookie("SETUP")));
1414 fprintf(file, "\n");
1418 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1420 fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
1422 /* just to make things nicer :) */
1423 if (i == SETUP_TOKEN_PLAYER_NAME || i == SETUP_TOKEN_GRAPHICS_SET - 1)
1424 fprintf(file, "\n");
1427 /* shortcut setup */
1428 ssi = setup.shortcut;
1429 fprintf(file, "\n");
1430 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1431 fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
1434 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1438 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1439 fprintf(file, "\n");
1441 sii = setup.input[pnr];
1442 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1443 fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
1448 SetFilePermissions(filename, PERMS_PRIVATE);