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
1182 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 19
1183 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 20
1184 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 21
1186 #define NUM_GLOBAL_SETUP_TOKENS 22
1188 /* shortcut setup */
1189 #define SETUP_TOKEN_SAVE_GAME 0
1190 #define SETUP_TOKEN_LOAD_GAME 1
1191 #define SETUP_TOKEN_TOGGLE_PAUSE 2
1193 #define NUM_SHORTCUT_SETUP_TOKENS 3
1196 #define SETUP_TOKEN_USE_JOYSTICK 0
1197 #define SETUP_TOKEN_JOY_DEVICE_NAME 1
1198 #define SETUP_TOKEN_JOY_XLEFT 2
1199 #define SETUP_TOKEN_JOY_XMIDDLE 3
1200 #define SETUP_TOKEN_JOY_XRIGHT 4
1201 #define SETUP_TOKEN_JOY_YUPPER 5
1202 #define SETUP_TOKEN_JOY_YMIDDLE 6
1203 #define SETUP_TOKEN_JOY_YLOWER 7
1204 #define SETUP_TOKEN_JOY_SNAP 8
1205 #define SETUP_TOKEN_JOY_BOMB 9
1206 #define SETUP_TOKEN_KEY_LEFT 10
1207 #define SETUP_TOKEN_KEY_RIGHT 11
1208 #define SETUP_TOKEN_KEY_UP 12
1209 #define SETUP_TOKEN_KEY_DOWN 13
1210 #define SETUP_TOKEN_KEY_SNAP 14
1211 #define SETUP_TOKEN_KEY_BOMB 15
1213 #define NUM_PLAYER_SETUP_TOKENS 16
1215 static struct SetupInfo si;
1216 static struct SetupShortcutInfo ssi;
1217 static struct SetupInputInfo sii;
1219 static struct TokenInfo global_setup_tokens[] =
1222 { TYPE_STRING, &si.player_name, "player_name" },
1223 { TYPE_SWITCH, &si.sound, "sound" },
1224 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
1225 { TYPE_SWITCH, &si.sound_music, "background_music" },
1226 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
1227 { TYPE_SWITCH, &si.toons, "toons" },
1228 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
1229 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
1230 { TYPE_SWITCH, &si.fading, "screen_fading" },
1231 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
1232 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
1233 { TYPE_SWITCH, &si.team_mode, "team_mode" },
1234 { TYPE_SWITCH, &si.handicap, "handicap" },
1235 { TYPE_SWITCH, &si.time_limit, "time_limit" },
1236 { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
1237 { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
1238 { TYPE_STRING, &si.graphics_set, "graphics_set" },
1239 { TYPE_STRING, &si.sounds_set, "sounds_set" },
1240 { TYPE_STRING, &si.music_set, "music_set" },
1241 { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
1242 { TYPE_SWITCH, &si.override_level_sounds, "override_level_sounds" },
1243 { TYPE_SWITCH, &si.override_level_music, "override_level_music" },
1246 static struct TokenInfo shortcut_setup_tokens[] =
1248 /* shortcut setup */
1249 { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
1250 { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
1251 { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }
1254 static struct TokenInfo player_setup_tokens[] =
1257 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
1258 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
1259 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
1260 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
1261 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
1262 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
1263 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
1264 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
1265 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
1266 { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
1267 { TYPE_KEY_X11, &sii.key.left, ".key.move_left" },
1268 { TYPE_KEY_X11, &sii.key.right, ".key.move_right" },
1269 { TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
1270 { TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
1271 { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
1272 { TYPE_KEY_X11, &sii.key.bomb, ".key.place_bomb" }
1275 static void setSetupInfoToDefaults(struct SetupInfo *si)
1279 si->player_name = getStringCopy(getLoginName());
1282 si->sound_loops = TRUE;
1283 si->sound_music = TRUE;
1284 si->sound_simple = TRUE;
1286 si->double_buffering = TRUE;
1287 si->direct_draw = !si->double_buffering;
1288 si->scroll_delay = TRUE;
1289 si->soft_scrolling = TRUE;
1291 si->autorecord = TRUE;
1292 si->quick_doors = FALSE;
1293 si->team_mode = FALSE;
1294 si->handicap = TRUE;
1295 si->time_limit = TRUE;
1296 si->fullscreen = FALSE;
1297 si->ask_on_escape = TRUE;
1299 si->graphics_set = getStringCopy(GRAPHICS_SUBDIR);
1300 si->sounds_set = getStringCopy(SOUNDS_SUBDIR);
1301 si->music_set = getStringCopy(MUSIC_SUBDIR);
1302 si->override_level_graphics = FALSE;
1303 si->override_level_sounds = FALSE;
1304 si->override_level_music = FALSE;
1306 si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
1307 si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
1308 si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
1310 for (i=0; i<MAX_PLAYERS; i++)
1312 si->input[i].use_joystick = FALSE;
1313 si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
1314 si->input[i].joy.xleft = JOYSTICK_XLEFT;
1315 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1316 si->input[i].joy.xright = JOYSTICK_XRIGHT;
1317 si->input[i].joy.yupper = JOYSTICK_YUPPER;
1318 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1319 si->input[i].joy.ylower = JOYSTICK_YLOWER;
1320 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
1321 si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
1322 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
1323 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
1324 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
1325 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
1326 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
1327 si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED);
1331 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
1335 if (!setup_file_list)
1340 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1341 setSetupInfo(global_setup_tokens, i,
1342 getTokenValue(setup_file_list, global_setup_tokens[i].text));
1345 /* shortcut setup */
1346 ssi = setup.shortcut;
1347 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1348 setSetupInfo(shortcut_setup_tokens, i,
1349 getTokenValue(setup_file_list,shortcut_setup_tokens[i].text));
1350 setup.shortcut = ssi;
1353 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1357 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1359 sii = setup.input[pnr];
1360 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1362 char full_token[100];
1364 sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
1365 setSetupInfo(player_setup_tokens, i,
1366 getTokenValue(setup_file_list, full_token));
1368 setup.input[pnr] = sii;
1374 char *filename = getSetupFilename();
1375 struct SetupFileList *setup_file_list = NULL;
1377 /* always start with reliable default values */
1378 setSetupInfoToDefaults(&setup);
1380 setup_file_list = loadSetupFileList(filename);
1382 if (setup_file_list)
1384 checkSetupFileListIdentifier(setup_file_list, getCookie("SETUP"));
1385 decodeSetupFileList(setup_file_list);
1387 setup.direct_draw = !setup.double_buffering;
1389 freeSetupFileList(setup_file_list);
1391 /* needed to work around problems with fixed length strings */
1392 if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN)
1393 setup.player_name[MAX_PLAYER_NAME_LEN] = '\0';
1394 else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN)
1396 char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
1398 strcpy(new_name, setup.player_name);
1399 free(setup.player_name);
1400 setup.player_name = new_name;
1404 Error(ERR_WARN, "using default setup values");
1409 char *filename = getSetupFilename();
1413 InitUserDataDirectory();
1415 if (!(file = fopen(filename, MODE_WRITE)))
1417 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1421 fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
1422 getCookie("SETUP")));
1423 fprintf(file, "\n");
1427 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1429 fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
1431 /* just to make things nicer :) */
1432 if (i == SETUP_TOKEN_PLAYER_NAME || i == SETUP_TOKEN_GRAPHICS_SET - 1)
1433 fprintf(file, "\n");
1436 /* shortcut setup */
1437 ssi = setup.shortcut;
1438 fprintf(file, "\n");
1439 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1440 fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
1443 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1447 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1448 fprintf(file, "\n");
1450 sii = setup.input[pnr];
1451 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1452 fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
1457 SetFilePermissions(filename, PERMS_PRIVATE);