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 3 /* unused tape header bytes */
35 /* file identifier strings */
36 #define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
37 #define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
38 #define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
41 /* ========================================================================= */
42 /* level file functions */
43 /* ========================================================================= */
45 static void setLevelInfoToDefaults()
49 level.file_version = FILE_VERSION_ACTUAL;
50 level.game_version = GAME_VERSION_ACTUAL;
52 level.encoding_16bit_field = FALSE; /* default: only 8-bit elements */
53 level.encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
54 level.encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
56 lev_fieldx = level.fieldx = STD_LEV_FIELDX;
57 lev_fieldy = level.fieldy = STD_LEV_FIELDY;
59 for(x=0; x<MAX_LEV_FIELDX; x++)
60 for(y=0; y<MAX_LEV_FIELDY; y++)
61 Feld[x][y] = Ur[x][y] = EL_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 level->file_version = getFileVersion(file);
144 level->game_version = getFileVersion(file);
149 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
153 lev_fieldx = level->fieldx = fgetc(file);
154 lev_fieldy = level->fieldy = fgetc(file);
156 level->time = getFile16BitBE(file);
157 level->gems_needed = getFile16BitBE(file);
159 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
160 level->name[i] = fgetc(file);
161 level->name[MAX_LEVEL_NAME_LEN] = 0;
163 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
164 level->score[i] = fgetc(file);
166 level->num_yam_contents = STD_ELEMENT_CONTENTS;
167 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
170 level->yam_content[i][x][y] = checkLevelElement(fgetc(file));
172 level->amoeba_speed = fgetc(file);
173 level->time_magic_wall = fgetc(file);
174 level->time_wheel = fgetc(file);
175 level->amoeba_content = checkLevelElement(fgetc(file));
176 level->double_speed = (fgetc(file) == 1 ? TRUE : FALSE);
177 level->gravity = (fgetc(file) == 1 ? TRUE : FALSE);
178 level->encoding_16bit_field = (fgetc(file) == 1 ? TRUE : FALSE);
179 level->em_slippery_gems = (fgetc(file) == 1 ? TRUE : FALSE);
181 ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
186 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
190 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
191 level->author[i] = fgetc(file);
192 level->author[MAX_LEVEL_NAME_LEN] = 0;
197 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
201 int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
202 int chunk_size_expected = header_size + content_size;
204 /* Note: "chunk_size" was wrong before version 2.0 when elements are
205 stored with 16-bit encoding (and should be twice as big then).
206 Even worse, playfield data was stored 16-bit when only yamyam content
207 contained 16-bit elements and vice versa. */
209 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
210 chunk_size_expected += content_size;
212 if (chunk_size_expected != chunk_size)
214 ReadUnusedBytesFromFile(file, chunk_size);
215 return chunk_size_expected;
219 level->num_yam_contents = fgetc(file);
223 /* correct invalid number of content fields -- should never happen */
224 if (level->num_yam_contents < 1 ||
225 level->num_yam_contents > MAX_ELEMENT_CONTENTS)
226 level->num_yam_contents = STD_ELEMENT_CONTENTS;
228 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
231 level->yam_content[i][x][y] =
232 checkLevelElement(level->encoding_16bit_field ?
233 getFile16BitBE(file) : fgetc(file));
237 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
240 int chunk_size_expected = level->fieldx * level->fieldy;
242 /* Note: "chunk_size" was wrong before version 2.0 when elements are
243 stored with 16-bit encoding (and should be twice as big then).
244 Even worse, playfield data was stored 16-bit when only yamyam content
245 contained 16-bit elements and vice versa. */
247 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
248 chunk_size_expected *= 2;
250 if (chunk_size_expected != chunk_size)
252 ReadUnusedBytesFromFile(file, chunk_size);
253 return chunk_size_expected;
256 for(y=0; y<level->fieldy; y++)
257 for(x=0; x<level->fieldx; x++)
258 Feld[x][y] = Ur[x][y] =
259 checkLevelElement(level->encoding_16bit_field ?
260 getFile16BitBE(file) : fgetc(file));
264 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
268 int num_contents, content_xsize, content_ysize;
269 int content_array[MAX_ELEMENT_CONTENTS][3][3];
271 element = checkLevelElement(getFile16BitBE(file));
272 num_contents = fgetc(file);
273 content_xsize = fgetc(file);
274 content_ysize = fgetc(file);
275 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
277 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
280 content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
282 /* correct invalid number of content fields -- should never happen */
283 if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
284 num_contents = STD_ELEMENT_CONTENTS;
286 if (element == EL_MAMPFER)
288 level->num_yam_contents = num_contents;
290 for(i=0; i<num_contents; i++)
293 level->yam_content[i][x][y] = content_array[i][x][y];
295 else if (element == EL_AMOEBE_BD)
297 level->amoeba_content = content_array[0][0][0];
301 Error(ERR_WARN, "cannot load content for element '%d'", element);
307 void LoadLevel(int level_nr)
309 char *filename = getLevelFilename(level_nr);
310 char cookie[MAX_LINE_LEN];
311 char chunk_name[CHUNK_ID_LEN + 1];
315 /* always start with reliable default values */
316 setLevelInfoToDefaults();
318 if (!(file = fopen(filename, MODE_READ)))
320 Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
324 getFileChunkBE(file, chunk_name, NULL);
325 if (strcmp(chunk_name, "RND1") == 0)
327 getFile32BitBE(file); /* not used */
329 getFileChunkBE(file, chunk_name, NULL);
330 if (strcmp(chunk_name, "CAVE") != 0)
332 Error(ERR_WARN, "unknown format of level file '%s'", filename);
337 else /* check for pre-2.0 file format with cookie string */
339 strcpy(cookie, chunk_name);
340 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
341 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
342 cookie[strlen(cookie) - 1] = '\0';
344 if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
346 Error(ERR_WARN, "unknown format of level file '%s'", filename);
351 if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
353 Error(ERR_WARN, "unsupported version of level file '%s'", filename);
358 /* pre-2.0 level files have no game version, so use file version here */
359 level.game_version = level.file_version;
362 if (level.file_version < FILE_VERSION_1_2)
364 /* level files from versions before 1.2.0 without chunk structure */
365 LoadLevel_HEAD(file, LEVEL_HEADER_SIZE, &level);
366 LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
374 int (*loader)(FILE *, int, struct LevelInfo *);
378 { "VERS", FILE_VERS_CHUNK_SIZE, LoadLevel_VERS },
379 { "HEAD", LEVEL_HEADER_SIZE, LoadLevel_HEAD },
380 { "AUTH", MAX_LEVEL_AUTHOR_LEN, LoadLevel_AUTH },
381 { "CONT", -1, LoadLevel_CONT },
382 { "BODY", -1, LoadLevel_BODY },
383 { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
387 while (getFileChunkBE(file, chunk_name, &chunk_size))
391 while (chunk_info[i].name != NULL &&
392 strcmp(chunk_name, chunk_info[i].name) != 0)
395 if (chunk_info[i].name == NULL)
397 Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
398 chunk_name, filename);
399 ReadUnusedBytesFromFile(file, chunk_size);
401 else if (chunk_info[i].size != -1 &&
402 chunk_info[i].size != chunk_size)
404 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
405 chunk_size, chunk_name, filename);
406 ReadUnusedBytesFromFile(file, chunk_size);
410 /* call function to load this level chunk */
411 int chunk_size_expected =
412 (chunk_info[i].loader)(file, chunk_size, &level);
414 /* the size of some chunks cannot be checked before reading other
415 chunks first (like "HEAD" and "BODY") that contain some header
416 information, so check them here */
417 if (chunk_size_expected != chunk_size)
419 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
420 chunk_size, chunk_name, filename);
428 if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
429 IS_LEVELCLASS_USER(leveldir_current))
431 /* For user contributed and private levels, use the version of
432 the game engine the levels were created for.
433 Since 2.0.1, the game engine version is now directly stored
434 in the level file (chunk "VERS"), so there is no need anymore
435 to set the game version from the file version (except for old,
436 pre-2.0 levels, where the game version is still taken from the
437 file format version used to store the level -- see above). */
439 /* do some special adjustments to support older level versions */
440 if (level.file_version == FILE_VERSION_1_0)
442 Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
443 Error(ERR_WARN, "using high speed movement for player");
445 /* player was faster than monsters in (pre-)1.0 levels */
446 level.double_speed = TRUE;
449 /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
450 if (level.game_version == VERSION_IDENT(2,0,1))
451 level.em_slippery_gems = TRUE;
455 /* Always use the latest version of the game engine for all but
456 user contributed and private levels; this allows for actual
457 corrections in the game engine to take effect for existing,
458 converted levels (from "classic" or other existing games) to
459 make the game emulation more accurate, while (hopefully) not
460 breaking existing levels created from other players. */
462 level.game_version = GAME_VERSION_ACTUAL;
464 /* Set special EM style gems behaviour: EM style gems slip down from
465 normal, steel and growing wall. As this is a more fundamental change,
466 it seems better to set the default behaviour to "off" (as it is more
467 natural) and make it configurable in the level editor (as a property
468 of gem style elements). Already existing converted levels (neither
469 private nor contributed levels) are changed to the new behaviour. */
471 if (level.file_version < FILE_VERSION_2_0)
472 level.em_slippery_gems = TRUE;
475 /* determine border element for this level */
479 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
481 putFileVersion(file, level->file_version);
482 putFileVersion(file, level->game_version);
485 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
489 fputc(level->fieldx, file);
490 fputc(level->fieldy, file);
492 putFile16BitBE(file, level->time);
493 putFile16BitBE(file, level->gems_needed);
495 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
496 fputc(level->name[i], file);
498 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
499 fputc(level->score[i], file);
501 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
504 fputc((level->encoding_16bit_yamyam ? EL_LEERRAUM :
505 level->yam_content[i][x][y]),
507 fputc(level->amoeba_speed, file);
508 fputc(level->time_magic_wall, file);
509 fputc(level->time_wheel, file);
510 fputc((level->encoding_16bit_amoeba ? EL_LEERRAUM : level->amoeba_content),
512 fputc((level->double_speed ? 1 : 0), file);
513 fputc((level->gravity ? 1 : 0), file);
514 fputc((level->encoding_16bit_field ? 1 : 0), file);
515 fputc((level->em_slippery_gems ? 1 : 0), file);
517 WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
520 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
524 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
525 fputc(level->author[i], file);
529 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
533 fputc(EL_MAMPFER, file);
534 fputc(level->num_yam_contents, file);
538 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
541 if (level->encoding_16bit_field)
542 putFile16BitBE(file, level->yam_content[i][x][y]);
544 fputc(level->yam_content[i][x][y], file);
548 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
552 for(y=0; y<level->fieldy; y++)
553 for(x=0; x<level->fieldx; x++)
554 if (level->encoding_16bit_field)
555 putFile16BitBE(file, Ur[x][y]);
557 fputc(Ur[x][y], file);
560 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
563 int num_contents, content_xsize, content_ysize;
564 int content_array[MAX_ELEMENT_CONTENTS][3][3];
566 if (element == EL_MAMPFER)
568 num_contents = level->num_yam_contents;
572 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
575 content_array[i][x][y] = level->yam_content[i][x][y];
577 else if (element == EL_AMOEBE_BD)
583 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
586 content_array[i][x][y] = EL_LEERRAUM;
587 content_array[0][0][0] = level->amoeba_content;
591 /* chunk header already written -- write empty chunk data */
592 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
594 Error(ERR_WARN, "cannot save content for element '%d'", element);
598 putFile16BitBE(file, element);
599 fputc(num_contents, file);
600 fputc(content_xsize, file);
601 fputc(content_ysize, file);
603 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
605 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
608 putFile16BitBE(file, content_array[i][x][y]);
611 void SaveLevel(int level_nr)
614 char *filename = getLevelFilename(level_nr);
618 if (!(file = fopen(filename, MODE_WRITE)))
620 Error(ERR_WARN, "cannot save level file '%s'", filename);
624 level.file_version = FILE_VERSION_ACTUAL;
625 level.game_version = GAME_VERSION_ACTUAL;
627 /* check level field for 16-bit elements */
628 level.encoding_16bit_field = FALSE;
629 for(y=0; y<level.fieldy; y++)
630 for(x=0; x<level.fieldx; x++)
632 level.encoding_16bit_field = TRUE;
634 /* check yamyam content for 16-bit elements */
635 level.encoding_16bit_yamyam = FALSE;
636 for(i=0; i<level.num_yam_contents; i++)
639 if (level.yam_content[i][x][y] > 255)
640 level.encoding_16bit_yamyam = TRUE;
642 /* check amoeba content for 16-bit elements */
643 level.encoding_16bit_amoeba = FALSE;
644 if (level.amoeba_content > 255)
645 level.encoding_16bit_amoeba = TRUE;
648 level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
650 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
651 putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
653 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
654 SaveLevel_VERS(file, &level);
656 putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
657 SaveLevel_HEAD(file, &level);
659 putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
660 SaveLevel_AUTH(file, &level);
662 putFileChunkBE(file, "BODY", body_chunk_size);
663 SaveLevel_BODY(file, &level);
665 if (level.encoding_16bit_yamyam ||
666 level.num_yam_contents != STD_ELEMENT_CONTENTS)
668 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
669 SaveLevel_CNT2(file, &level, EL_MAMPFER);
672 if (level.encoding_16bit_amoeba)
674 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
675 SaveLevel_CNT2(file, &level, EL_AMOEBE_BD);
680 SetFilePermissions(filename, PERMS_PRIVATE);
684 /* ========================================================================= */
685 /* tape file functions */
686 /* ========================================================================= */
688 static void setTapeInfoToDefaults()
692 /* always start with reliable default values (empty tape) */
693 tape.file_version = FILE_VERSION_ACTUAL;
694 tape.game_version = GAME_VERSION_ACTUAL;
697 /* default values (also for pre-1.2 tapes) with only the first player */
698 tape.player_participates[0] = TRUE;
699 for(i=1; i<MAX_PLAYERS; i++)
700 tape.player_participates[i] = FALSE;
702 /* at least one (default: the first) player participates in every tape */
703 tape.num_participating_players = 1;
705 tape.level_nr = level_nr;
707 tape.changed = FALSE;
709 tape.recording = FALSE;
710 tape.playing = FALSE;
711 tape.pausing = FALSE;
714 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
716 tape->file_version = getFileVersion(file);
717 tape->game_version = getFileVersion(file);
722 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
726 tape->random_seed = getFile32BitBE(file);
727 tape->date = getFile32BitBE(file);
728 tape->length = getFile32BitBE(file);
730 /* read header fields that are new since version 1.2 */
731 if (tape->file_version >= FILE_VERSION_1_2)
733 byte store_participating_players = fgetc(file);
735 ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
737 /* since version 1.2, tapes store which players participate in the tape */
738 tape->num_participating_players = 0;
739 for(i=0; i<MAX_PLAYERS; i++)
741 tape->player_participates[i] = FALSE;
743 if (store_participating_players & (1 << i))
745 tape->player_participates[i] = TRUE;
746 tape->num_participating_players++;
750 ReadUnusedBytesFromFile(file, 4);
756 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
759 int chunk_size_expected =
760 (tape->num_participating_players + 1) * tape->length;
762 if (chunk_size_expected != chunk_size)
764 ReadUnusedBytesFromFile(file, chunk_size);
765 return chunk_size_expected;
768 for(i=0; i<tape->length; i++)
770 if (i >= MAX_TAPELEN)
773 for(j=0; j<MAX_PLAYERS; j++)
775 tape->pos[i].action[j] = MV_NO_MOVING;
777 if (tape->player_participates[j])
778 tape->pos[i].action[j] = fgetc(file);
781 tape->pos[i].delay = fgetc(file);
783 if (tape->file_version == FILE_VERSION_1_0)
785 /* eliminate possible diagonal moves in old tapes */
786 /* this is only for backward compatibility */
788 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
789 byte action = tape->pos[i].action[0];
790 int k, num_moves = 0;
794 if (action & joy_dir[k])
796 tape->pos[i + num_moves].action[0] = joy_dir[k];
798 tape->pos[i + num_moves].delay = 0;
807 tape->length += num_moves;
810 else if (tape->file_version < FILE_VERSION_2_0)
812 /* convert pre-2.0 tapes to new tape format */
814 if (tape->pos[i].delay > 1)
817 tape->pos[i + 1] = tape->pos[i];
818 tape->pos[i + 1].delay = 1;
821 for(j=0; j<MAX_PLAYERS; j++)
822 tape->pos[i].action[j] = MV_NO_MOVING;
823 tape->pos[i].delay--;
834 if (i != tape->length)
835 chunk_size = (tape->num_participating_players + 1) * i;
840 void LoadTape(int level_nr)
842 char *filename = getTapeFilename(level_nr);
843 char cookie[MAX_LINE_LEN];
844 char chunk_name[CHUNK_ID_LEN + 1];
848 /* always start with reliable default values */
849 setTapeInfoToDefaults();
851 if (!(file = fopen(filename, MODE_READ)))
854 getFileChunkBE(file, chunk_name, NULL);
855 if (strcmp(chunk_name, "RND1") == 0)
857 getFile32BitBE(file); /* not used */
859 getFileChunkBE(file, chunk_name, NULL);
860 if (strcmp(chunk_name, "TAPE") != 0)
862 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
867 else /* check for pre-2.0 file format with cookie string */
869 strcpy(cookie, chunk_name);
870 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
871 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
872 cookie[strlen(cookie) - 1] = '\0';
874 if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
876 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
881 if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
883 Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
888 /* pre-2.0 tape files have no game version, so use file version here */
889 tape.game_version = tape.file_version;
892 if (tape.file_version < FILE_VERSION_1_2)
894 /* tape files from versions before 1.2.0 without chunk structure */
895 LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
896 LoadTape_BODY(file, 2 * tape.length, &tape);
904 int (*loader)(FILE *, int, struct TapeInfo *);
908 { "VERS", FILE_VERS_CHUNK_SIZE, LoadTape_VERS },
909 { "HEAD", TAPE_HEADER_SIZE, LoadTape_HEAD },
910 { "BODY", -1, LoadTape_BODY },
914 while (getFileChunkBE(file, chunk_name, &chunk_size))
918 while (chunk_info[i].name != NULL &&
919 strcmp(chunk_name, chunk_info[i].name) != 0)
922 if (chunk_info[i].name == NULL)
924 Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
925 chunk_name, filename);
926 ReadUnusedBytesFromFile(file, chunk_size);
928 else if (chunk_info[i].size != -1 &&
929 chunk_info[i].size != chunk_size)
931 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
932 chunk_size, chunk_name, filename);
933 ReadUnusedBytesFromFile(file, chunk_size);
937 /* call function to load this tape chunk */
938 int chunk_size_expected =
939 (chunk_info[i].loader)(file, chunk_size, &tape);
941 /* the size of some chunks cannot be checked before reading other
942 chunks first (like "HEAD" and "BODY") that contain some header
943 information, so check them here */
944 if (chunk_size_expected != chunk_size)
946 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
947 chunk_size, chunk_name, filename);
955 tape.length_seconds = GetTapeLength();
958 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
960 putFileVersion(file, tape->file_version);
961 putFileVersion(file, tape->game_version);
964 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
967 byte store_participating_players = 0;
969 /* set bits for participating players for compact storage */
970 for(i=0; i<MAX_PLAYERS; i++)
971 if (tape->player_participates[i])
972 store_participating_players |= (1 << i);
974 putFile32BitBE(file, tape->random_seed);
975 putFile32BitBE(file, tape->date);
976 putFile32BitBE(file, tape->length);
978 fputc(store_participating_players, file);
980 WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
982 WriteUnusedBytesToFile(file, 4);
985 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
989 for(i=0; i<tape->length; i++)
991 for(j=0; j<MAX_PLAYERS; j++)
992 if (tape->player_participates[j])
993 fputc(tape->pos[i].action[j], file);
995 fputc(tape->pos[i].delay, file);
999 void SaveTape(int level_nr)
1002 char *filename = getTapeFilename(level_nr);
1004 boolean new_tape = TRUE;
1005 int num_participating_players = 0;
1006 int body_chunk_size;
1008 InitTapeDirectory(leveldir_current->filename);
1010 /* if a tape still exists, ask to overwrite it */
1011 if (access(filename, F_OK) == 0)
1014 if (!Request("Replace old tape ?", REQ_ASK))
1018 if (!(file = fopen(filename, MODE_WRITE)))
1020 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
1024 tape.file_version = FILE_VERSION_ACTUAL;
1025 tape.game_version = GAME_VERSION_ACTUAL;
1027 /* count number of participating players */
1028 for(i=0; i<MAX_PLAYERS; i++)
1029 if (tape.player_participates[i])
1030 num_participating_players++;
1032 body_chunk_size = (num_participating_players + 1) * tape.length;
1034 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1035 putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
1037 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1038 SaveTape_VERS(file, &tape);
1040 putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
1041 SaveTape_HEAD(file, &tape);
1043 putFileChunkBE(file, "BODY", body_chunk_size);
1044 SaveTape_BODY(file, &tape);
1048 SetFilePermissions(filename, PERMS_PRIVATE);
1050 tape.changed = FALSE;
1053 Request("tape saved !", REQ_CONFIRM);
1056 void DumpTape(struct TapeInfo *tape)
1060 if (TAPE_IS_EMPTY(*tape))
1062 Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
1067 printf("-------------------------------------------------------------------------------\n");
1068 printf("Tape of Level %d (file version %06d, game version %06d\n",
1069 tape->level_nr, tape->file_version, tape->game_version);
1070 printf("-------------------------------------------------------------------------------\n");
1072 for(i=0; i<tape->length; i++)
1074 if (i >= MAX_TAPELEN)
1077 for(j=0; j<MAX_PLAYERS; j++)
1079 if (tape->player_participates[j])
1081 int action = tape->pos[i].action[j];
1083 printf("%d:%02x ", j, action);
1084 printf("[%c%c%c%c|%c%c] - ",
1085 (action & JOY_LEFT ? '<' : ' '),
1086 (action & JOY_RIGHT ? '>' : ' '),
1087 (action & JOY_UP ? '^' : ' '),
1088 (action & JOY_DOWN ? 'v' : ' '),
1089 (action & JOY_BUTTON_1 ? '1' : ' '),
1090 (action & JOY_BUTTON_2 ? '2' : ' '));
1094 printf("(%03d)\n", tape->pos[i].delay);
1097 printf("-------------------------------------------------------------------------------\n");
1101 /* ========================================================================= */
1102 /* score file functions */
1103 /* ========================================================================= */
1105 void LoadScore(int level_nr)
1108 char *filename = getScoreFilename(level_nr);
1109 char cookie[MAX_LINE_LEN];
1110 char line[MAX_LINE_LEN];
1114 /* always start with reliable default values */
1115 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1117 strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
1118 highscore[i].Score = 0;
1121 if (!(file = fopen(filename, MODE_READ)))
1124 /* check file identifier */
1125 fgets(cookie, MAX_LINE_LEN, file);
1126 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1127 cookie[strlen(cookie) - 1] = '\0';
1129 if (!checkCookieString(cookie, SCORE_COOKIE))
1131 Error(ERR_WARN, "unknown format of score file '%s'", filename);
1136 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1138 fscanf(file, "%d", &highscore[i].Score);
1139 fgets(line, MAX_LINE_LEN, file);
1141 if (line[strlen(line) - 1] == '\n')
1142 line[strlen(line) - 1] = '\0';
1144 for (line_ptr = line; *line_ptr; line_ptr++)
1146 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
1148 strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
1149 highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
1158 void SaveScore(int level_nr)
1161 char *filename = getScoreFilename(level_nr);
1164 InitScoreDirectory(leveldir_current->filename);
1166 if (!(file = fopen(filename, MODE_WRITE)))
1168 Error(ERR_WARN, "cannot save score for level %d", level_nr);
1172 fprintf(file, "%s\n\n", SCORE_COOKIE);
1174 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1175 fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
1179 SetFilePermissions(filename, PERMS_PUBLIC);
1183 /* ========================================================================= */
1184 /* setup file functions */
1185 /* ========================================================================= */
1187 #define TOKEN_STR_PLAYER_PREFIX "player_"
1190 #define SETUP_TOKEN_PLAYER_NAME 0
1191 #define SETUP_TOKEN_SOUND 1
1192 #define SETUP_TOKEN_SOUND_LOOPS 2
1193 #define SETUP_TOKEN_SOUND_MUSIC 3
1194 #define SETUP_TOKEN_SOUND_SIMPLE 4
1195 #define SETUP_TOKEN_TOONS 5
1196 #define SETUP_TOKEN_SCROLL_DELAY 6
1197 #define SETUP_TOKEN_SOFT_SCROLLING 7
1198 #define SETUP_TOKEN_FADING 8
1199 #define SETUP_TOKEN_AUTORECORD 9
1200 #define SETUP_TOKEN_QUICK_DOORS 10
1201 #define SETUP_TOKEN_TEAM_MODE 11
1202 #define SETUP_TOKEN_HANDICAP 12
1203 #define SETUP_TOKEN_TIME_LIMIT 13
1204 #define SETUP_TOKEN_FULLSCREEN 14
1205 #define SETUP_TOKEN_ASK_ON_ESCAPE 15
1206 #define SETUP_TOKEN_GRAPHICS_SET 16
1207 #define SETUP_TOKEN_SOUNDS_SET 17
1208 #define SETUP_TOKEN_MUSIC_SET 18
1209 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 19
1210 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 20
1211 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 21
1213 #define NUM_GLOBAL_SETUP_TOKENS 22
1215 /* shortcut setup */
1216 #define SETUP_TOKEN_SAVE_GAME 0
1217 #define SETUP_TOKEN_LOAD_GAME 1
1218 #define SETUP_TOKEN_TOGGLE_PAUSE 2
1220 #define NUM_SHORTCUT_SETUP_TOKENS 3
1223 #define SETUP_TOKEN_USE_JOYSTICK 0
1224 #define SETUP_TOKEN_JOY_DEVICE_NAME 1
1225 #define SETUP_TOKEN_JOY_XLEFT 2
1226 #define SETUP_TOKEN_JOY_XMIDDLE 3
1227 #define SETUP_TOKEN_JOY_XRIGHT 4
1228 #define SETUP_TOKEN_JOY_YUPPER 5
1229 #define SETUP_TOKEN_JOY_YMIDDLE 6
1230 #define SETUP_TOKEN_JOY_YLOWER 7
1231 #define SETUP_TOKEN_JOY_SNAP 8
1232 #define SETUP_TOKEN_JOY_BOMB 9
1233 #define SETUP_TOKEN_KEY_LEFT 10
1234 #define SETUP_TOKEN_KEY_RIGHT 11
1235 #define SETUP_TOKEN_KEY_UP 12
1236 #define SETUP_TOKEN_KEY_DOWN 13
1237 #define SETUP_TOKEN_KEY_SNAP 14
1238 #define SETUP_TOKEN_KEY_BOMB 15
1240 #define NUM_PLAYER_SETUP_TOKENS 16
1242 static struct SetupInfo si;
1243 static struct SetupShortcutInfo ssi;
1244 static struct SetupInputInfo sii;
1246 static struct TokenInfo global_setup_tokens[] =
1249 { TYPE_STRING, &si.player_name, "player_name" },
1250 { TYPE_SWITCH, &si.sound, "sound" },
1251 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
1252 { TYPE_SWITCH, &si.sound_music, "background_music" },
1253 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
1254 { TYPE_SWITCH, &si.toons, "toons" },
1255 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
1256 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
1257 { TYPE_SWITCH, &si.fading, "screen_fading" },
1258 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
1259 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
1260 { TYPE_SWITCH, &si.team_mode, "team_mode" },
1261 { TYPE_SWITCH, &si.handicap, "handicap" },
1262 { TYPE_SWITCH, &si.time_limit, "time_limit" },
1263 { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
1264 { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
1265 { TYPE_STRING, &si.graphics_set, "graphics_set" },
1266 { TYPE_STRING, &si.sounds_set, "sounds_set" },
1267 { TYPE_STRING, &si.music_set, "music_set" },
1268 { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
1269 { TYPE_SWITCH, &si.override_level_sounds, "override_level_sounds" },
1270 { TYPE_SWITCH, &si.override_level_music, "override_level_music" },
1273 static struct TokenInfo shortcut_setup_tokens[] =
1275 /* shortcut setup */
1276 { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
1277 { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
1278 { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }
1281 static struct TokenInfo player_setup_tokens[] =
1284 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
1285 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
1286 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
1287 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
1288 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
1289 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
1290 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
1291 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
1292 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
1293 { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
1294 { TYPE_KEY_X11, &sii.key.left, ".key.move_left" },
1295 { TYPE_KEY_X11, &sii.key.right, ".key.move_right" },
1296 { TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
1297 { TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
1298 { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
1299 { TYPE_KEY_X11, &sii.key.bomb, ".key.place_bomb" }
1302 static void setSetupInfoToDefaults(struct SetupInfo *si)
1306 si->player_name = getStringCopy(getLoginName());
1309 si->sound_loops = TRUE;
1310 si->sound_music = TRUE;
1311 si->sound_simple = TRUE;
1313 si->double_buffering = TRUE;
1314 si->direct_draw = !si->double_buffering;
1315 si->scroll_delay = TRUE;
1316 si->soft_scrolling = TRUE;
1318 si->autorecord = TRUE;
1319 si->quick_doors = FALSE;
1320 si->team_mode = FALSE;
1321 si->handicap = TRUE;
1322 si->time_limit = TRUE;
1323 si->fullscreen = FALSE;
1324 si->ask_on_escape = TRUE;
1326 si->graphics_set = getStringCopy(GRAPHICS_SUBDIR);
1327 si->sounds_set = getStringCopy(SOUNDS_SUBDIR);
1328 si->music_set = getStringCopy(MUSIC_SUBDIR);
1329 si->override_level_graphics = FALSE;
1330 si->override_level_sounds = FALSE;
1331 si->override_level_music = FALSE;
1333 si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
1334 si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
1335 si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
1337 for (i=0; i<MAX_PLAYERS; i++)
1339 si->input[i].use_joystick = FALSE;
1340 si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
1341 si->input[i].joy.xleft = JOYSTICK_XLEFT;
1342 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1343 si->input[i].joy.xright = JOYSTICK_XRIGHT;
1344 si->input[i].joy.yupper = JOYSTICK_YUPPER;
1345 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1346 si->input[i].joy.ylower = JOYSTICK_YLOWER;
1347 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
1348 si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
1349 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
1350 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
1351 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
1352 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
1353 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
1354 si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED);
1358 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
1362 if (!setup_file_list)
1367 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1368 setSetupInfo(global_setup_tokens, i,
1369 getTokenValue(setup_file_list, global_setup_tokens[i].text));
1372 /* shortcut setup */
1373 ssi = setup.shortcut;
1374 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1375 setSetupInfo(shortcut_setup_tokens, i,
1376 getTokenValue(setup_file_list,shortcut_setup_tokens[i].text));
1377 setup.shortcut = ssi;
1380 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1384 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1386 sii = setup.input[pnr];
1387 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1389 char full_token[100];
1391 sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
1392 setSetupInfo(player_setup_tokens, i,
1393 getTokenValue(setup_file_list, full_token));
1395 setup.input[pnr] = sii;
1401 char *filename = getSetupFilename();
1402 struct SetupFileList *setup_file_list = NULL;
1404 /* always start with reliable default values */
1405 setSetupInfoToDefaults(&setup);
1407 setup_file_list = loadSetupFileList(filename);
1409 if (setup_file_list)
1411 checkSetupFileListIdentifier(setup_file_list, getCookie("SETUP"));
1412 decodeSetupFileList(setup_file_list);
1414 setup.direct_draw = !setup.double_buffering;
1416 freeSetupFileList(setup_file_list);
1418 /* needed to work around problems with fixed length strings */
1419 if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN)
1420 setup.player_name[MAX_PLAYER_NAME_LEN] = '\0';
1421 else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN)
1423 char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
1425 strcpy(new_name, setup.player_name);
1426 free(setup.player_name);
1427 setup.player_name = new_name;
1431 Error(ERR_WARN, "using default setup values");
1436 char *filename = getSetupFilename();
1440 InitUserDataDirectory();
1442 if (!(file = fopen(filename, MODE_WRITE)))
1444 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1448 fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
1449 getCookie("SETUP")));
1450 fprintf(file, "\n");
1454 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1456 fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
1458 /* just to make things nicer :) */
1459 if (i == SETUP_TOKEN_PLAYER_NAME || i == SETUP_TOKEN_GRAPHICS_SET - 1)
1460 fprintf(file, "\n");
1463 /* shortcut setup */
1464 ssi = setup.shortcut;
1465 fprintf(file, "\n");
1466 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1467 fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
1470 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1474 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1475 fprintf(file, "\n");
1477 sii = setup.input[pnr];
1478 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1479 fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
1484 SetFilePermissions(filename, PERMS_PRIVATE);