1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
17 #include "libgame/libgame.h"
25 #define CHUNK_ID_LEN 4 /* IFF style chunk id length */
26 #define CHUNK_SIZE_UNDEFINED 0 /* undefined chunk size == 0 */
27 #define CHUNK_SIZE_NONE -1 /* do not write chunk size */
28 #define FILE_VERS_CHUNK_SIZE 8 /* size of file version chunk */
29 #define LEVEL_HEADER_SIZE 80 /* size of level file header */
30 #define LEVEL_HEADER_UNUSED 13 /* unused level header bytes */
31 #define LEVEL_CHUNK_CNT2_SIZE 160 /* size of level CNT2 chunk */
32 #define LEVEL_CHUNK_CNT2_UNUSED 11 /* unused CNT2 chunk bytes */
33 #define LEVEL_CPART_CUS3_SIZE 134 /* size of CUS3 chunk part */
34 #define LEVEL_CPART_CUS3_UNUSED 15 /* unused CUS3 bytes / part */
35 #define TAPE_HEADER_SIZE 20 /* size of tape file header */
36 #define TAPE_HEADER_UNUSED 3 /* unused tape header bytes */
38 #define LEVEL_CHUNK_CUS3_SIZE(x) (2 + x * LEVEL_CPART_CUS3_SIZE)
40 /* file identifier strings */
41 #define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
42 #define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
43 #define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
46 /* ========================================================================= */
47 /* level file functions */
48 /* ========================================================================= */
50 static void setLevelInfoToDefaults()
54 level.file_version = FILE_VERSION_ACTUAL;
55 level.game_version = GAME_VERSION_ACTUAL;
57 level.encoding_16bit_field = FALSE; /* default: only 8-bit elements */
58 level.encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
59 level.encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
61 lev_fieldx = level.fieldx = STD_LEV_FIELDX;
62 lev_fieldy = level.fieldy = STD_LEV_FIELDY;
64 for(x=0; x<MAX_LEV_FIELDX; x++)
65 for(y=0; y<MAX_LEV_FIELDY; y++)
66 Feld[x][y] = Ur[x][y] = EL_SAND;
69 level.gems_needed = 0;
70 level.amoeba_speed = 10;
71 level.time_magic_wall = 10;
72 level.time_wheel = 10;
73 level.time_light = 10;
74 level.time_timegate = 10;
75 level.amoeba_content = EL_DIAMOND;
76 level.double_speed = FALSE;
77 level.gravity = FALSE;
78 level.em_slippery_gems = FALSE;
80 level.use_custom_template = FALSE;
82 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
84 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
85 level.author[i] = '\0';
87 strcpy(level.name, NAMELESS_LEVEL_NAME);
88 strcpy(level.author, ANONYMOUS_NAME);
90 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
93 level.num_yamyam_contents = STD_ELEMENT_CONTENTS;
94 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
97 level.yamyam_content[i][x][y] =
98 (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
100 Feld[0][0] = Ur[0][0] = EL_PLAYER_1;
101 Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
102 Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_EXIT_CLOSED;
104 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
106 int element = EL_CUSTOM_START + i;
108 for(j=0; j<MAX_ELEMENT_NAME_LEN + 1; j++)
109 element_info[element].description[j] = '\0';
110 if (element_info[element].custom_description != NULL)
111 strncpy(element_info[element].description,
112 element_info[element].custom_description, MAX_ELEMENT_NAME_LEN);
114 strcpy(element_info[element].description,
115 element_info[element].editor_description);
117 element_info[element].use_gfx_element = FALSE;
118 element_info[element].gfx_element = EL_EMPTY_SPACE;
120 element_info[element].score = 0;
121 element_info[element].gem_count = 0;
123 element_info[element].push_delay_fixed = 2; /* special default */
124 element_info[element].push_delay_random = 8; /* special default */
125 element_info[element].move_delay_fixed = 0;
126 element_info[element].move_delay_random = 0;
128 element_info[element].move_pattern = MV_ALL_DIRECTIONS;
129 element_info[element].move_direction_initial = MV_NO_MOVING;
130 element_info[element].move_stepsize = TILEX / 8;
132 element_info[element].slippery_type = SLIPPERY_ANY_RANDOM;
136 element_info[element].content[x][y] = EL_EMPTY_SPACE;
138 element_info[element].change.events = CE_BITMASK_DEFAULT;
139 element_info[element].change.target_element = EL_EMPTY_SPACE;
141 element_info[element].change.delay_fixed = 0;
142 element_info[element].change.delay_random = 0;
143 element_info[element].change.delay_frames = -1; /* use default */
145 element_info[element].change.trigger_element = EL_EMPTY_SPACE;
147 element_info[element].change.explode = FALSE;
148 element_info[element].change.use_content = FALSE;
149 element_info[element].change.only_complete = FALSE;
150 element_info[element].change.use_random_change = FALSE;
151 element_info[element].change.random = 0;
152 element_info[element].change.power = CP_NON_DESTRUCTIVE;
156 element_info[element].change.content[x][y] = EL_EMPTY_SPACE;
158 element_info[element].access_type = 0;
159 element_info[element].access_layer = 0;
160 element_info[element].walk_to_action = 0;
161 element_info[element].smash_targets = 0;
162 element_info[element].deadliness = 0;
163 element_info[element].consistency = 0;
164 element_info[element].change_player_action = 0;
165 element_info[element].change_collide_action = 0;
166 element_info[element].change_other_action = 0;
168 element_info[element].can_explode_by_fire = FALSE;
169 element_info[element].can_explode_smashed = FALSE;
170 element_info[element].can_explode_impact = FALSE;
172 /* start with no properties at all */
173 for (j=0; j < NUM_EP_BITFIELDS; j++)
174 Properties[element][j] = EP_BITMASK_DEFAULT;
177 BorderElement = EL_STEELWALL;
179 level.no_level_file = FALSE;
181 if (leveldir_current == NULL) /* only when dumping level */
184 /* try to determine better author name than 'anonymous' */
185 if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
187 strncpy(level.author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
188 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
192 switch (LEVELCLASS(leveldir_current))
194 case LEVELCLASS_TUTORIAL:
195 strcpy(level.author, PROGRAM_AUTHOR_STRING);
198 case LEVELCLASS_CONTRIBUTION:
199 strncpy(level.author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN);
200 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
203 case LEVELCLASS_USER:
204 strncpy(level.author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
205 level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
209 /* keep default value */
215 static int checkLevelElement(int element)
217 if (element >= NUM_FILE_ELEMENTS)
219 Error(ERR_WARN, "invalid level element %d", element);
220 element = EL_CHAR_QUESTION;
222 else if (element == EL_PLAYER_OBSOLETE)
223 element = EL_PLAYER_1;
224 else if (element == EL_KEY_OBSOLETE)
230 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
232 level->file_version = getFileVersion(file);
233 level->game_version = getFileVersion(file);
238 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
242 lev_fieldx = level->fieldx = fgetc(file);
243 lev_fieldy = level->fieldy = fgetc(file);
245 level->time = getFile16BitBE(file);
246 level->gems_needed = getFile16BitBE(file);
248 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
249 level->name[i] = fgetc(file);
250 level->name[MAX_LEVEL_NAME_LEN] = 0;
252 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
253 level->score[i] = fgetc(file);
255 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
256 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
259 level->yamyam_content[i][x][y] = checkLevelElement(fgetc(file));
261 level->amoeba_speed = fgetc(file);
262 level->time_magic_wall = fgetc(file);
263 level->time_wheel = fgetc(file);
264 level->amoeba_content = checkLevelElement(fgetc(file));
265 level->double_speed = (fgetc(file) == 1 ? TRUE : FALSE);
266 level->gravity = (fgetc(file) == 1 ? TRUE : FALSE);
267 level->encoding_16bit_field = (fgetc(file) == 1 ? TRUE : FALSE);
268 level->em_slippery_gems = (fgetc(file) == 1 ? TRUE : FALSE);
270 level->use_custom_template = (fgetc(file) == 1 ? TRUE : FALSE);
272 ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
277 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
281 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
282 level->author[i] = fgetc(file);
283 level->author[MAX_LEVEL_NAME_LEN] = 0;
288 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
291 int chunk_size_expected = level->fieldx * level->fieldy;
293 /* Note: "chunk_size" was wrong before version 2.0 when elements are
294 stored with 16-bit encoding (and should be twice as big then).
295 Even worse, playfield data was stored 16-bit when only yamyam content
296 contained 16-bit elements and vice versa. */
298 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
299 chunk_size_expected *= 2;
301 if (chunk_size_expected != chunk_size)
303 ReadUnusedBytesFromFile(file, chunk_size);
304 return chunk_size_expected;
307 for(y=0; y<level->fieldy; y++)
308 for(x=0; x<level->fieldx; x++)
309 Feld[x][y] = Ur[x][y] =
310 checkLevelElement(level->encoding_16bit_field ?
311 getFile16BitBE(file) : fgetc(file));
315 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
319 int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
320 int chunk_size_expected = header_size + content_size;
322 /* Note: "chunk_size" was wrong before version 2.0 when elements are
323 stored with 16-bit encoding (and should be twice as big then).
324 Even worse, playfield data was stored 16-bit when only yamyam content
325 contained 16-bit elements and vice versa. */
327 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
328 chunk_size_expected += content_size;
330 if (chunk_size_expected != chunk_size)
332 ReadUnusedBytesFromFile(file, chunk_size);
333 return chunk_size_expected;
337 level->num_yamyam_contents = fgetc(file);
341 /* correct invalid number of content fields -- should never happen */
342 if (level->num_yamyam_contents < 1 ||
343 level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
344 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
346 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
349 level->yamyam_content[i][x][y] =
350 checkLevelElement(level->encoding_16bit_field ?
351 getFile16BitBE(file) : fgetc(file));
355 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
359 int num_contents, content_xsize, content_ysize;
360 int content_array[MAX_ELEMENT_CONTENTS][3][3];
362 element = checkLevelElement(getFile16BitBE(file));
363 num_contents = fgetc(file);
364 content_xsize = fgetc(file);
365 content_ysize = fgetc(file);
366 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
368 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
371 content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
373 /* correct invalid number of content fields -- should never happen */
374 if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
375 num_contents = STD_ELEMENT_CONTENTS;
377 if (element == EL_YAMYAM)
379 level->num_yamyam_contents = num_contents;
381 for(i=0; i<num_contents; i++)
384 level->yamyam_content[i][x][y] = content_array[i][x][y];
386 else if (element == EL_BD_AMOEBA)
388 level->amoeba_content = content_array[0][0][0];
392 Error(ERR_WARN, "cannot load content for element '%d'", element);
398 static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
400 int num_changed_custom_elements = getFile16BitBE(file);
401 int chunk_size_expected = 2 + num_changed_custom_elements * 6;
404 if (chunk_size_expected != chunk_size)
406 ReadUnusedBytesFromFile(file, chunk_size - 2);
407 return chunk_size_expected;
410 for (i=0; i < num_changed_custom_elements; i++)
412 int element = getFile16BitBE(file);
413 int properties = getFile32BitBE(file);
415 if (IS_CUSTOM_ELEMENT(element))
416 Properties[element][EP_BITFIELD_BASE] = properties;
418 Error(ERR_WARN, "invalid custom element number %d", element);
424 static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
426 int num_changed_custom_elements = getFile16BitBE(file);
427 int chunk_size_expected = 2 + num_changed_custom_elements * 4;
430 if (chunk_size_expected != chunk_size)
432 ReadUnusedBytesFromFile(file, chunk_size - 2);
433 return chunk_size_expected;
436 for (i=0; i < num_changed_custom_elements; i++)
438 int element = getFile16BitBE(file);
439 int custom_target_element = getFile16BitBE(file);
441 if (IS_CUSTOM_ELEMENT(element))
442 element_info[element].change.target_element = custom_target_element;
444 Error(ERR_WARN, "invalid custom element number %d", element);
450 static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
452 int num_changed_custom_elements = getFile16BitBE(file);
453 int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
456 if (chunk_size_expected != chunk_size)
458 ReadUnusedBytesFromFile(file, chunk_size - 2);
459 return chunk_size_expected;
462 for (i=0; i < num_changed_custom_elements; i++)
464 int element = getFile16BitBE(file);
466 if (!IS_CUSTOM_ELEMENT(element))
468 Error(ERR_WARN, "invalid custom element number %d", element);
470 element = EL_DEFAULT; /* dummy element used for artwork config */
473 for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
474 element_info[element].description[j] = getFile8Bit(file);
475 element_info[element].description[MAX_ELEMENT_NAME_LEN] = 0;
477 Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
479 /* some free bytes for future properties and padding */
480 ReadUnusedBytesFromFile(file, 7);
482 element_info[element].use_gfx_element = getFile8Bit(file);
483 element_info[element].gfx_element =
484 checkLevelElement(getFile16BitBE(file));
486 element_info[element].score = getFile8Bit(file);
487 element_info[element].gem_count = getFile8Bit(file);
489 element_info[element].push_delay_fixed = getFile16BitBE(file);
490 element_info[element].push_delay_random = getFile16BitBE(file);
491 element_info[element].move_delay_fixed = getFile16BitBE(file);
492 element_info[element].move_delay_random = getFile16BitBE(file);
494 element_info[element].move_pattern = getFile16BitBE(file);
495 element_info[element].move_direction_initial = getFile8Bit(file);
496 element_info[element].move_stepsize = getFile8Bit(file);
500 element_info[element].content[x][y] =
501 checkLevelElement(getFile16BitBE(file));
503 element_info[element].change.events = getFile32BitBE(file);
505 element_info[element].change.target_element =
506 checkLevelElement(getFile16BitBE(file));
508 element_info[element].change.delay_fixed = getFile16BitBE(file);
509 element_info[element].change.delay_random = getFile16BitBE(file);
510 element_info[element].change.delay_frames = getFile16BitBE(file);
512 element_info[element].change.trigger_element =
513 checkLevelElement(getFile16BitBE(file));
515 element_info[element].change.explode = getFile8Bit(file);
516 element_info[element].change.use_content = getFile8Bit(file);
517 element_info[element].change.only_complete = getFile8Bit(file);
518 element_info[element].change.use_random_change = getFile8Bit(file);
520 element_info[element].change.random = getFile8Bit(file);
521 element_info[element].change.power = getFile8Bit(file);
525 element_info[element].change.content[x][y] =
526 checkLevelElement(getFile16BitBE(file));
528 element_info[element].slippery_type = getFile8Bit(file);
530 /* some free bytes for future properties and padding */
531 ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
537 void LoadLevelFromFilename(char *filename)
539 char cookie[MAX_LINE_LEN];
540 char chunk_name[CHUNK_ID_LEN + 1];
544 /* always start with reliable default values */
545 setLevelInfoToDefaults();
547 if (!(file = fopen(filename, MODE_READ)))
549 level.no_level_file = TRUE;
551 Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
555 getFileChunkBE(file, chunk_name, NULL);
556 if (strcmp(chunk_name, "RND1") == 0)
558 getFile32BitBE(file); /* not used */
560 getFileChunkBE(file, chunk_name, NULL);
561 if (strcmp(chunk_name, "CAVE") != 0)
563 Error(ERR_WARN, "unknown format of level file '%s'", filename);
568 else /* check for pre-2.0 file format with cookie string */
570 strcpy(cookie, chunk_name);
571 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
572 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
573 cookie[strlen(cookie) - 1] = '\0';
575 if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
577 Error(ERR_WARN, "unknown format of level file '%s'", filename);
582 if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
584 Error(ERR_WARN, "unsupported version of level file '%s'", filename);
589 /* pre-2.0 level files have no game version, so use file version here */
590 level.game_version = level.file_version;
593 if (level.file_version < FILE_VERSION_1_2)
595 /* level files from versions before 1.2.0 without chunk structure */
596 LoadLevel_HEAD(file, LEVEL_HEADER_SIZE, &level);
597 LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
605 int (*loader)(FILE *, int, struct LevelInfo *);
609 { "VERS", FILE_VERS_CHUNK_SIZE, LoadLevel_VERS },
610 { "HEAD", LEVEL_HEADER_SIZE, LoadLevel_HEAD },
611 { "AUTH", MAX_LEVEL_AUTHOR_LEN, LoadLevel_AUTH },
612 { "BODY", -1, LoadLevel_BODY },
613 { "CONT", -1, LoadLevel_CONT },
614 { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
615 { "CUS1", -1, LoadLevel_CUS1 },
616 { "CUS2", -1, LoadLevel_CUS2 },
617 { "CUS3", -1, LoadLevel_CUS3 },
621 while (getFileChunkBE(file, chunk_name, &chunk_size))
625 while (chunk_info[i].name != NULL &&
626 strcmp(chunk_name, chunk_info[i].name) != 0)
629 if (chunk_info[i].name == NULL)
631 Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
632 chunk_name, filename);
633 ReadUnusedBytesFromFile(file, chunk_size);
635 else if (chunk_info[i].size != -1 &&
636 chunk_info[i].size != chunk_size)
638 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
639 chunk_size, chunk_name, filename);
640 ReadUnusedBytesFromFile(file, chunk_size);
644 /* call function to load this level chunk */
645 int chunk_size_expected =
646 (chunk_info[i].loader)(file, chunk_size, &level);
648 /* the size of some chunks cannot be checked before reading other
649 chunks first (like "HEAD" and "BODY") that contain some header
650 information, so check them here */
651 if (chunk_size_expected != chunk_size)
653 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
654 chunk_size, chunk_name, filename);
662 if (leveldir_current == NULL) /* only when dumping level */
665 if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
666 IS_LEVELCLASS_USER(leveldir_current))
668 /* For user contributed and private levels, use the version of
669 the game engine the levels were created for.
670 Since 2.0.1, the game engine version is now directly stored
671 in the level file (chunk "VERS"), so there is no need anymore
672 to set the game version from the file version (except for old,
673 pre-2.0 levels, where the game version is still taken from the
674 file format version used to store the level -- see above). */
676 /* do some special adjustments to support older level versions */
677 if (level.file_version == FILE_VERSION_1_0)
679 Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
680 Error(ERR_WARN, "using high speed movement for player");
682 /* player was faster than monsters in (pre-)1.0 levels */
683 level.double_speed = TRUE;
686 /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
687 if (level.game_version == VERSION_IDENT(2,0,1))
688 level.em_slippery_gems = TRUE;
692 /* Always use the latest version of the game engine for all but
693 user contributed and private levels; this allows for actual
694 corrections in the game engine to take effect for existing,
695 converted levels (from "classic" or other existing games) to
696 make the game emulation more accurate, while (hopefully) not
697 breaking existing levels created from other players. */
699 level.game_version = GAME_VERSION_ACTUAL;
701 /* Set special EM style gems behaviour: EM style gems slip down from
702 normal, steel and growing wall. As this is a more fundamental change,
703 it seems better to set the default behaviour to "off" (as it is more
704 natural) and make it configurable in the level editor (as a property
705 of gem style elements). Already existing converted levels (neither
706 private nor contributed levels) are changed to the new behaviour. */
708 if (level.file_version < FILE_VERSION_2_0)
709 level.em_slippery_gems = TRUE;
712 /* map some elements which have changed in newer versions */
713 if (level.game_version <= VERSION_IDENT(2,2,0))
717 /* map game font elements */
718 for(y=0; y<level.fieldy; y++)
720 for(x=0; x<level.fieldx; x++)
722 int element = Ur[x][y];
724 if (element == EL_CHAR('['))
725 element = EL_CHAR_AUMLAUT;
726 else if (element == EL_CHAR('\\'))
727 element = EL_CHAR_OUMLAUT;
728 else if (element == EL_CHAR(']'))
729 element = EL_CHAR_UUMLAUT;
730 else if (element == EL_CHAR('^'))
731 element = EL_CHAR_COPYRIGHT;
733 Feld[x][y] = Ur[x][y] = element;
738 /* determine border element for this level */
742 void LoadLevel(int level_nr)
744 char *filename = getLevelFilename(level_nr);
746 LoadLevelFromFilename(filename);
747 InitElementPropertiesEngine(level.game_version);
750 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
752 putFileVersion(file, level->file_version);
753 putFileVersion(file, level->game_version);
756 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
760 fputc(level->fieldx, file);
761 fputc(level->fieldy, file);
763 putFile16BitBE(file, level->time);
764 putFile16BitBE(file, level->gems_needed);
766 for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
767 fputc(level->name[i], file);
769 for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
770 fputc(level->score[i], file);
772 for(i=0; i<STD_ELEMENT_CONTENTS; i++)
775 fputc((level->encoding_16bit_yamyam ? EL_EMPTY :
776 level->yamyam_content[i][x][y]),
778 fputc(level->amoeba_speed, file);
779 fputc(level->time_magic_wall, file);
780 fputc(level->time_wheel, file);
781 fputc((level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content),
783 fputc((level->double_speed ? 1 : 0), file);
784 fputc((level->gravity ? 1 : 0), file);
785 fputc((level->encoding_16bit_field ? 1 : 0), file);
786 fputc((level->em_slippery_gems ? 1 : 0), file);
788 fputc((level->use_custom_template ? 1 : 0), file);
790 WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
793 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
797 for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
798 fputc(level->author[i], file);
801 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
805 for(y=0; y<level->fieldy; y++)
806 for(x=0; x<level->fieldx; x++)
807 if (level->encoding_16bit_field)
808 putFile16BitBE(file, Ur[x][y]);
810 fputc(Ur[x][y], file);
814 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
818 fputc(EL_YAMYAM, file);
819 fputc(level->num_yamyam_contents, file);
823 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
826 if (level->encoding_16bit_field)
827 putFile16BitBE(file, level->yamyam_content[i][x][y]);
829 fputc(level->yamyam_content[i][x][y], file);
833 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
836 int num_contents, content_xsize, content_ysize;
837 int content_array[MAX_ELEMENT_CONTENTS][3][3];
839 if (element == EL_YAMYAM)
841 num_contents = level->num_yamyam_contents;
845 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
848 content_array[i][x][y] = level->yamyam_content[i][x][y];
850 else if (element == EL_BD_AMOEBA)
856 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
859 content_array[i][x][y] = EL_EMPTY;
860 content_array[0][0][0] = level->amoeba_content;
864 /* chunk header already written -- write empty chunk data */
865 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
867 Error(ERR_WARN, "cannot save content for element '%d'", element);
871 putFile16BitBE(file, element);
872 fputc(num_contents, file);
873 fputc(content_xsize, file);
874 fputc(content_ysize, file);
876 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
878 for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
881 putFile16BitBE(file, content_array[i][x][y]);
885 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
886 int num_changed_custom_elements)
890 putFile16BitBE(file, num_changed_custom_elements);
892 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
894 int element = EL_CUSTOM_START + i;
896 if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
898 if (check < num_changed_custom_elements)
900 putFile16BitBE(file, element);
901 putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
908 if (check != num_changed_custom_elements) /* should not happen */
909 Error(ERR_WARN, "inconsistent number of custom element properties");
914 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
915 int num_changed_custom_elements)
919 putFile16BitBE(file, num_changed_custom_elements);
921 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
923 int element = EL_CUSTOM_START + i;
925 if (element_info[element].change.target_element != EL_EMPTY_SPACE)
927 if (check < num_changed_custom_elements)
929 putFile16BitBE(file, element);
930 putFile16BitBE(file, element_info[element].change.target_element);
937 if (check != num_changed_custom_elements) /* should not happen */
938 Error(ERR_WARN, "inconsistent number of custom target elements");
942 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
943 int num_changed_custom_elements)
945 int i, j, x, y, check = 0;
947 putFile16BitBE(file, num_changed_custom_elements);
949 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
951 int element = EL_CUSTOM_START + i;
953 if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
955 if (check < num_changed_custom_elements)
957 putFile16BitBE(file, element);
959 for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
960 putFile8Bit(file, element_info[element].description[j]);
962 putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
964 /* some free bytes for future properties and padding */
965 WriteUnusedBytesToFile(file, 7);
967 putFile8Bit(file, element_info[element].use_gfx_element);
968 putFile16BitBE(file, element_info[element].gfx_element);
970 putFile8Bit(file, element_info[element].score);
971 putFile8Bit(file, element_info[element].gem_count);
973 putFile16BitBE(file, element_info[element].push_delay_fixed);
974 putFile16BitBE(file, element_info[element].push_delay_random);
975 putFile16BitBE(file, element_info[element].move_delay_fixed);
976 putFile16BitBE(file, element_info[element].move_delay_random);
978 putFile16BitBE(file, element_info[element].move_pattern);
979 putFile8Bit(file, element_info[element].move_direction_initial);
980 putFile8Bit(file, element_info[element].move_stepsize);
984 putFile16BitBE(file, element_info[element].content[x][y]);
986 putFile32BitBE(file, element_info[element].change.events);
988 putFile16BitBE(file, element_info[element].change.target_element);
990 putFile16BitBE(file, element_info[element].change.delay_fixed);
991 putFile16BitBE(file, element_info[element].change.delay_random);
992 putFile16BitBE(file, element_info[element].change.delay_frames);
994 putFile16BitBE(file, element_info[element].change.trigger_element);
996 putFile8Bit(file, element_info[element].change.explode);
997 putFile8Bit(file, element_info[element].change.use_content);
998 putFile8Bit(file, element_info[element].change.only_complete);
999 putFile8Bit(file, element_info[element].change.use_random_change);
1001 putFile8Bit(file, element_info[element].change.random);
1002 putFile8Bit(file, element_info[element].change.power);
1006 putFile16BitBE(file, element_info[element].change.content[x][y]);
1008 putFile8Bit(file, element_info[element].slippery_type);
1010 /* some free bytes for future properties and padding */
1011 WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
1018 if (check != num_changed_custom_elements) /* should not happen */
1019 Error(ERR_WARN, "inconsistent number of custom element properties");
1022 void SaveLevel(int level_nr)
1024 char *filename = getLevelFilename(level_nr);
1025 int body_chunk_size;
1026 int num_changed_custom_elements = 0;
1027 int level_chunk_CUS3_size;
1031 if (!(file = fopen(filename, MODE_WRITE)))
1033 Error(ERR_WARN, "cannot save level file '%s'", filename);
1037 level.file_version = FILE_VERSION_ACTUAL;
1038 level.game_version = GAME_VERSION_ACTUAL;
1040 /* check level field for 16-bit elements */
1041 level.encoding_16bit_field = FALSE;
1042 for(y=0; y<level.fieldy; y++)
1043 for(x=0; x<level.fieldx; x++)
1045 level.encoding_16bit_field = TRUE;
1047 /* check yamyam content for 16-bit elements */
1048 level.encoding_16bit_yamyam = FALSE;
1049 for(i=0; i<level.num_yamyam_contents; i++)
1052 if (level.yamyam_content[i][x][y] > 255)
1053 level.encoding_16bit_yamyam = TRUE;
1055 /* check amoeba content for 16-bit elements */
1056 level.encoding_16bit_amoeba = FALSE;
1057 if (level.amoeba_content > 255)
1058 level.encoding_16bit_amoeba = TRUE;
1060 /* calculate size of "BODY" chunk */
1062 level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
1064 /* check for non-standard custom elements and calculate "CUS3" chunk size */
1065 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1066 if (Properties[EL_CUSTOM_START +i][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
1067 num_changed_custom_elements++;
1068 level_chunk_CUS3_size = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
1070 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1071 putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
1073 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1074 SaveLevel_VERS(file, &level);
1076 putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
1077 SaveLevel_HEAD(file, &level);
1079 putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
1080 SaveLevel_AUTH(file, &level);
1082 putFileChunkBE(file, "BODY", body_chunk_size);
1083 SaveLevel_BODY(file, &level);
1085 if (level.encoding_16bit_yamyam ||
1086 level.num_yamyam_contents != STD_ELEMENT_CONTENTS)
1088 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
1089 SaveLevel_CNT2(file, &level, EL_YAMYAM);
1092 if (level.encoding_16bit_amoeba)
1094 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
1095 SaveLevel_CNT2(file, &level, EL_BD_AMOEBA);
1098 if (num_changed_custom_elements > 0)
1100 putFileChunkBE(file, "CUS3", level_chunk_CUS3_size);
1101 SaveLevel_CUS3(file, &level, num_changed_custom_elements);
1106 SetFilePermissions(filename, PERMS_PRIVATE);
1109 void DumpLevel(struct LevelInfo *level)
1111 printf_line("-", 79);
1112 printf("Level xxx (file version %08d, game version %08d)\n",
1113 level->file_version, level->game_version);
1114 printf_line("-", 79);
1116 printf("Level Author: '%s'\n", level->author);
1117 printf("Level Title: '%s'\n", level->name);
1119 printf("Playfield Size: %d x %d\n", level->fieldx, level->fieldy);
1121 printf("Level Time: %d seconds\n", level->time);
1122 printf("Gems needed: %d\n", level->gems_needed);
1124 printf("Time for Magic Wall: %d seconds\n", level->time_magic_wall);
1125 printf("Time for Wheel: %d seconds\n", level->time_wheel);
1126 printf("Time for Light: %d seconds\n", level->time_light);
1127 printf("Time for Timegate: %d seconds\n", level->time_timegate);
1129 printf("Amoeba Speed: %d\n", level->amoeba_speed);
1131 printf("Gravity: %s\n", (level->gravity ? "yes" : "no"));
1132 printf("Double Speed Movement: %s\n", (level->double_speed ? "yes" : "no"));
1133 printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
1135 printf_line("-", 79);
1139 /* ========================================================================= */
1140 /* tape file functions */
1141 /* ========================================================================= */
1143 static void setTapeInfoToDefaults()
1147 /* always start with reliable default values (empty tape) */
1150 /* default values (also for pre-1.2 tapes) with only the first player */
1151 tape.player_participates[0] = TRUE;
1152 for(i=1; i<MAX_PLAYERS; i++)
1153 tape.player_participates[i] = FALSE;
1155 /* at least one (default: the first) player participates in every tape */
1156 tape.num_participating_players = 1;
1158 tape.level_nr = level_nr;
1160 tape.changed = FALSE;
1162 tape.recording = FALSE;
1163 tape.playing = FALSE;
1164 tape.pausing = FALSE;
1167 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
1169 tape->file_version = getFileVersion(file);
1170 tape->game_version = getFileVersion(file);
1175 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
1179 tape->random_seed = getFile32BitBE(file);
1180 tape->date = getFile32BitBE(file);
1181 tape->length = getFile32BitBE(file);
1183 /* read header fields that are new since version 1.2 */
1184 if (tape->file_version >= FILE_VERSION_1_2)
1186 byte store_participating_players = fgetc(file);
1189 /* since version 1.2, tapes store which players participate in the tape */
1190 tape->num_participating_players = 0;
1191 for(i=0; i<MAX_PLAYERS; i++)
1193 tape->player_participates[i] = FALSE;
1195 if (store_participating_players & (1 << i))
1197 tape->player_participates[i] = TRUE;
1198 tape->num_participating_players++;
1202 ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
1204 engine_version = getFileVersion(file);
1205 if (engine_version > 0)
1206 tape->engine_version = engine_version;
1212 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
1214 int level_identifier_size;
1217 level_identifier_size = getFile16BitBE(file);
1219 tape->level_identifier =
1220 checked_realloc(tape->level_identifier, level_identifier_size);
1222 for(i=0; i < level_identifier_size; i++)
1223 tape->level_identifier[i] = fgetc(file);
1225 tape->level_nr = getFile16BitBE(file);
1227 chunk_size = 2 + level_identifier_size + 2;
1232 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
1235 int chunk_size_expected =
1236 (tape->num_participating_players + 1) * tape->length;
1238 if (chunk_size_expected != chunk_size)
1240 ReadUnusedBytesFromFile(file, chunk_size);
1241 return chunk_size_expected;
1244 for(i=0; i<tape->length; i++)
1246 if (i >= MAX_TAPELEN)
1249 for(j=0; j<MAX_PLAYERS; j++)
1251 tape->pos[i].action[j] = MV_NO_MOVING;
1253 if (tape->player_participates[j])
1254 tape->pos[i].action[j] = fgetc(file);
1257 tape->pos[i].delay = fgetc(file);
1259 if (tape->file_version == FILE_VERSION_1_0)
1261 /* eliminate possible diagonal moves in old tapes */
1262 /* this is only for backward compatibility */
1264 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
1265 byte action = tape->pos[i].action[0];
1266 int k, num_moves = 0;
1270 if (action & joy_dir[k])
1272 tape->pos[i + num_moves].action[0] = joy_dir[k];
1274 tape->pos[i + num_moves].delay = 0;
1283 tape->length += num_moves;
1286 else if (tape->file_version < FILE_VERSION_2_0)
1288 /* convert pre-2.0 tapes to new tape format */
1290 if (tape->pos[i].delay > 1)
1293 tape->pos[i + 1] = tape->pos[i];
1294 tape->pos[i + 1].delay = 1;
1297 for(j=0; j<MAX_PLAYERS; j++)
1298 tape->pos[i].action[j] = MV_NO_MOVING;
1299 tape->pos[i].delay--;
1310 if (i != tape->length)
1311 chunk_size = (tape->num_participating_players + 1) * i;
1316 void LoadTapeFromFilename(char *filename)
1318 char cookie[MAX_LINE_LEN];
1319 char chunk_name[CHUNK_ID_LEN + 1];
1323 /* always start with reliable default values */
1324 setTapeInfoToDefaults();
1326 if (!(file = fopen(filename, MODE_READ)))
1329 getFileChunkBE(file, chunk_name, NULL);
1330 if (strcmp(chunk_name, "RND1") == 0)
1332 getFile32BitBE(file); /* not used */
1334 getFileChunkBE(file, chunk_name, NULL);
1335 if (strcmp(chunk_name, "TAPE") != 0)
1337 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
1342 else /* check for pre-2.0 file format with cookie string */
1344 strcpy(cookie, chunk_name);
1345 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
1346 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1347 cookie[strlen(cookie) - 1] = '\0';
1349 if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
1351 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
1356 if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
1358 Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
1363 /* pre-2.0 tape files have no game version, so use file version here */
1364 tape.game_version = tape.file_version;
1367 if (tape.file_version < FILE_VERSION_1_2)
1369 /* tape files from versions before 1.2.0 without chunk structure */
1370 LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
1371 LoadTape_BODY(file, 2 * tape.length, &tape);
1379 int (*loader)(FILE *, int, struct TapeInfo *);
1383 { "VERS", FILE_VERS_CHUNK_SIZE, LoadTape_VERS },
1384 { "HEAD", TAPE_HEADER_SIZE, LoadTape_HEAD },
1385 { "INFO", -1, LoadTape_INFO },
1386 { "BODY", -1, LoadTape_BODY },
1390 while (getFileChunkBE(file, chunk_name, &chunk_size))
1394 while (chunk_info[i].name != NULL &&
1395 strcmp(chunk_name, chunk_info[i].name) != 0)
1398 if (chunk_info[i].name == NULL)
1400 Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
1401 chunk_name, filename);
1402 ReadUnusedBytesFromFile(file, chunk_size);
1404 else if (chunk_info[i].size != -1 &&
1405 chunk_info[i].size != chunk_size)
1407 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
1408 chunk_size, chunk_name, filename);
1409 ReadUnusedBytesFromFile(file, chunk_size);
1413 /* call function to load this tape chunk */
1414 int chunk_size_expected =
1415 (chunk_info[i].loader)(file, chunk_size, &tape);
1417 /* the size of some chunks cannot be checked before reading other
1418 chunks first (like "HEAD" and "BODY") that contain some header
1419 information, so check them here */
1420 if (chunk_size_expected != chunk_size)
1422 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
1423 chunk_size, chunk_name, filename);
1431 tape.length_seconds = GetTapeLength();
1434 printf("tape version: %d\n", tape.game_version);
1438 void LoadTape(int level_nr)
1440 char *filename = getTapeFilename(level_nr);
1442 LoadTapeFromFilename(filename);
1445 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
1447 putFileVersion(file, tape->file_version);
1448 putFileVersion(file, tape->game_version);
1451 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
1454 byte store_participating_players = 0;
1456 /* set bits for participating players for compact storage */
1457 for(i=0; i<MAX_PLAYERS; i++)
1458 if (tape->player_participates[i])
1459 store_participating_players |= (1 << i);
1461 putFile32BitBE(file, tape->random_seed);
1462 putFile32BitBE(file, tape->date);
1463 putFile32BitBE(file, tape->length);
1465 fputc(store_participating_players, file);
1467 /* unused bytes not at the end here for 4-byte alignment of engine_version */
1468 WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
1470 putFileVersion(file, tape->engine_version);
1473 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
1475 int level_identifier_size = strlen(tape->level_identifier) + 1;
1478 putFile16BitBE(file, level_identifier_size);
1480 for(i=0; i < level_identifier_size; i++)
1481 fputc(tape->level_identifier[i], file);
1483 putFile16BitBE(file, tape->level_nr);
1486 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
1490 for(i=0; i<tape->length; i++)
1492 for(j=0; j<MAX_PLAYERS; j++)
1493 if (tape->player_participates[j])
1494 fputc(tape->pos[i].action[j], file);
1496 fputc(tape->pos[i].delay, file);
1500 void SaveTape(int level_nr)
1502 char *filename = getTapeFilename(level_nr);
1504 boolean new_tape = TRUE;
1505 int num_participating_players = 0;
1506 int info_chunk_size;
1507 int body_chunk_size;
1510 InitTapeDirectory(leveldir_current->filename);
1512 /* if a tape still exists, ask to overwrite it */
1513 if (access(filename, F_OK) == 0)
1516 if (!Request("Replace old tape ?", REQ_ASK))
1520 if (!(file = fopen(filename, MODE_WRITE)))
1522 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
1526 tape.file_version = FILE_VERSION_ACTUAL;
1527 tape.game_version = GAME_VERSION_ACTUAL;
1529 /* count number of participating players */
1530 for(i=0; i<MAX_PLAYERS; i++)
1531 if (tape.player_participates[i])
1532 num_participating_players++;
1534 info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
1535 body_chunk_size = (num_participating_players + 1) * tape.length;
1537 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1538 putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
1540 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1541 SaveTape_VERS(file, &tape);
1543 putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
1544 SaveTape_HEAD(file, &tape);
1546 putFileChunkBE(file, "INFO", info_chunk_size);
1547 SaveTape_INFO(file, &tape);
1549 putFileChunkBE(file, "BODY", body_chunk_size);
1550 SaveTape_BODY(file, &tape);
1554 SetFilePermissions(filename, PERMS_PRIVATE);
1556 tape.changed = FALSE;
1559 Request("tape saved !", REQ_CONFIRM);
1562 void DumpTape(struct TapeInfo *tape)
1566 if (TAPE_IS_EMPTY(*tape))
1568 Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
1572 printf_line("-", 79);
1573 printf("Tape of Level %03d (file version %08d, game version %08d)\n",
1574 tape->level_nr, tape->file_version, tape->game_version);
1575 printf("Level series identifier: '%s'\n", tape->level_identifier);
1576 printf_line("-", 79);
1578 for(i=0; i<tape->length; i++)
1580 if (i >= MAX_TAPELEN)
1583 printf("%03d: ", i);
1585 for(j=0; j<MAX_PLAYERS; j++)
1587 if (tape->player_participates[j])
1589 int action = tape->pos[i].action[j];
1591 printf("%d:%02x ", j, action);
1592 printf("[%c%c%c%c|%c%c] - ",
1593 (action & JOY_LEFT ? '<' : ' '),
1594 (action & JOY_RIGHT ? '>' : ' '),
1595 (action & JOY_UP ? '^' : ' '),
1596 (action & JOY_DOWN ? 'v' : ' '),
1597 (action & JOY_BUTTON_1 ? '1' : ' '),
1598 (action & JOY_BUTTON_2 ? '2' : ' '));
1602 printf("(%03d)\n", tape->pos[i].delay);
1605 printf_line("-", 79);
1609 /* ========================================================================= */
1610 /* score file functions */
1611 /* ========================================================================= */
1613 void LoadScore(int level_nr)
1616 char *filename = getScoreFilename(level_nr);
1617 char cookie[MAX_LINE_LEN];
1618 char line[MAX_LINE_LEN];
1622 /* always start with reliable default values */
1623 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1625 strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
1626 highscore[i].Score = 0;
1629 if (!(file = fopen(filename, MODE_READ)))
1632 /* check file identifier */
1633 fgets(cookie, MAX_LINE_LEN, file);
1634 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1635 cookie[strlen(cookie) - 1] = '\0';
1637 if (!checkCookieString(cookie, SCORE_COOKIE))
1639 Error(ERR_WARN, "unknown format of score file '%s'", filename);
1644 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1646 fscanf(file, "%d", &highscore[i].Score);
1647 fgets(line, MAX_LINE_LEN, file);
1649 if (line[strlen(line) - 1] == '\n')
1650 line[strlen(line) - 1] = '\0';
1652 for (line_ptr = line; *line_ptr; line_ptr++)
1654 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
1656 strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
1657 highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
1666 void SaveScore(int level_nr)
1669 char *filename = getScoreFilename(level_nr);
1672 InitScoreDirectory(leveldir_current->filename);
1674 if (!(file = fopen(filename, MODE_WRITE)))
1676 Error(ERR_WARN, "cannot save score for level %d", level_nr);
1680 fprintf(file, "%s\n\n", SCORE_COOKIE);
1682 for(i=0; i<MAX_SCORE_ENTRIES; i++)
1683 fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
1687 SetFilePermissions(filename, PERMS_PUBLIC);
1691 /* ========================================================================= */
1692 /* setup file functions */
1693 /* ========================================================================= */
1695 #define TOKEN_STR_PLAYER_PREFIX "player_"
1698 #define SETUP_TOKEN_PLAYER_NAME 0
1699 #define SETUP_TOKEN_SOUND 1
1700 #define SETUP_TOKEN_SOUND_LOOPS 2
1701 #define SETUP_TOKEN_SOUND_MUSIC 3
1702 #define SETUP_TOKEN_SOUND_SIMPLE 4
1703 #define SETUP_TOKEN_TOONS 5
1704 #define SETUP_TOKEN_SCROLL_DELAY 6
1705 #define SETUP_TOKEN_SOFT_SCROLLING 7
1706 #define SETUP_TOKEN_FADING 8
1707 #define SETUP_TOKEN_AUTORECORD 9
1708 #define SETUP_TOKEN_QUICK_DOORS 10
1709 #define SETUP_TOKEN_TEAM_MODE 11
1710 #define SETUP_TOKEN_HANDICAP 12
1711 #define SETUP_TOKEN_TIME_LIMIT 13
1712 #define SETUP_TOKEN_FULLSCREEN 14
1713 #define SETUP_TOKEN_ASK_ON_ESCAPE 15
1714 #define SETUP_TOKEN_GRAPHICS_SET 16
1715 #define SETUP_TOKEN_SOUNDS_SET 17
1716 #define SETUP_TOKEN_MUSIC_SET 18
1717 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 19
1718 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 20
1719 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 21
1721 #define NUM_GLOBAL_SETUP_TOKENS 22
1724 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH 0
1725 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE 1
1726 #define SETUP_TOKEN_EDITOR_EL_MORE 2
1727 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN 3
1728 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX 4
1729 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES 5
1730 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH 6
1731 #define SETUP_TOKEN_EDITOR_EL_CHARS 7
1732 #define SETUP_TOKEN_EDITOR_EL_CUSTOM 8
1734 #define NUM_EDITOR_SETUP_TOKENS 9
1736 /* shortcut setup */
1737 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0
1738 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME 1
1739 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE 2
1741 #define NUM_SHORTCUT_SETUP_TOKENS 3
1744 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK 0
1745 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME 1
1746 #define SETUP_TOKEN_PLAYER_JOY_XLEFT 2
1747 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE 3
1748 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT 4
1749 #define SETUP_TOKEN_PLAYER_JOY_YUPPER 5
1750 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE 6
1751 #define SETUP_TOKEN_PLAYER_JOY_YLOWER 7
1752 #define SETUP_TOKEN_PLAYER_JOY_SNAP 8
1753 #define SETUP_TOKEN_PLAYER_JOY_BOMB 9
1754 #define SETUP_TOKEN_PLAYER_KEY_LEFT 10
1755 #define SETUP_TOKEN_PLAYER_KEY_RIGHT 11
1756 #define SETUP_TOKEN_PLAYER_KEY_UP 12
1757 #define SETUP_TOKEN_PLAYER_KEY_DOWN 13
1758 #define SETUP_TOKEN_PLAYER_KEY_SNAP 14
1759 #define SETUP_TOKEN_PLAYER_KEY_BOMB 15
1761 #define NUM_PLAYER_SETUP_TOKENS 16
1764 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER 0
1765 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 1
1767 #define NUM_SYSTEM_SETUP_TOKENS 2
1770 #define SETUP_TOKEN_OPTIONS_VERBOSE 0
1772 #define NUM_OPTIONS_SETUP_TOKENS 1
1775 static struct SetupInfo si;
1776 static struct SetupEditorInfo sei;
1777 static struct SetupShortcutInfo ssi;
1778 static struct SetupInputInfo sii;
1779 static struct SetupSystemInfo syi;
1780 static struct OptionInfo soi;
1782 static struct TokenInfo global_setup_tokens[] =
1784 { TYPE_STRING, &si.player_name, "player_name" },
1785 { TYPE_SWITCH, &si.sound, "sound" },
1786 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
1787 { TYPE_SWITCH, &si.sound_music, "background_music" },
1788 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
1789 { TYPE_SWITCH, &si.toons, "toons" },
1790 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
1791 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
1792 { TYPE_SWITCH, &si.fading, "screen_fading" },
1793 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
1794 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
1795 { TYPE_SWITCH, &si.team_mode, "team_mode" },
1796 { TYPE_SWITCH, &si.handicap, "handicap" },
1797 { TYPE_SWITCH, &si.time_limit, "time_limit" },
1798 { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
1799 { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
1800 { TYPE_STRING, &si.graphics_set, "graphics_set" },
1801 { TYPE_STRING, &si.sounds_set, "sounds_set" },
1802 { TYPE_STRING, &si.music_set, "music_set" },
1803 { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
1804 { TYPE_SWITCH, &si.override_level_sounds, "override_level_sounds" },
1805 { TYPE_SWITCH, &si.override_level_music, "override_level_music" },
1808 static struct TokenInfo editor_setup_tokens[] =
1810 { TYPE_SWITCH, &sei.el_boulderdash, "editor.el_boulderdash" },
1811 { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine" },
1812 { TYPE_SWITCH, &sei.el_more, "editor.el_more" },
1813 { TYPE_SWITCH, &sei.el_sokoban, "editor.el_sokoban" },
1814 { TYPE_SWITCH, &sei.el_supaplex, "editor.el_supaplex" },
1815 { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves" },
1816 { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash" },
1817 { TYPE_SWITCH, &sei.el_chars, "editor.el_chars" },
1818 { TYPE_SWITCH, &sei.el_custom, "editor.el_custom" },
1821 static struct TokenInfo shortcut_setup_tokens[] =
1823 { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
1824 { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
1825 { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }
1828 static struct TokenInfo player_setup_tokens[] =
1830 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
1831 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
1832 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
1833 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
1834 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
1835 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
1836 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
1837 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
1838 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
1839 { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
1840 { TYPE_KEY_X11, &sii.key.left, ".key.move_left" },
1841 { TYPE_KEY_X11, &sii.key.right, ".key.move_right" },
1842 { TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
1843 { TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
1844 { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
1845 { TYPE_KEY_X11, &sii.key.bomb, ".key.place_bomb" }
1848 static struct TokenInfo system_setup_tokens[] =
1850 { TYPE_STRING, &syi.sdl_audiodriver, "system.sdl_audiodriver" },
1851 { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }
1854 static struct TokenInfo options_setup_tokens[] =
1856 { TYPE_BOOLEAN, &soi.verbose, "options.verbose" }
1859 static char *get_corrected_login_name(char *login_name)
1861 /* needed because player name must be a fixed length string */
1862 char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
1864 strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
1865 login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
1867 if (strlen(login_name) > MAX_PLAYER_NAME_LEN) /* name has been cut */
1868 if (strchr(login_name_new, ' '))
1869 *strchr(login_name_new, ' ') = '\0';
1871 return login_name_new;
1874 static void setSetupInfoToDefaults(struct SetupInfo *si)
1878 si->player_name = get_corrected_login_name(getLoginName());
1881 si->sound_loops = TRUE;
1882 si->sound_music = TRUE;
1883 si->sound_simple = TRUE;
1885 si->double_buffering = TRUE;
1886 si->direct_draw = !si->double_buffering;
1887 si->scroll_delay = TRUE;
1888 si->soft_scrolling = TRUE;
1890 si->autorecord = TRUE;
1891 si->quick_doors = FALSE;
1892 si->team_mode = FALSE;
1893 si->handicap = TRUE;
1894 si->time_limit = TRUE;
1895 si->fullscreen = FALSE;
1896 si->ask_on_escape = TRUE;
1898 si->graphics_set = getStringCopy(GRAPHICS_SUBDIR);
1899 si->sounds_set = getStringCopy(SOUNDS_SUBDIR);
1900 si->music_set = getStringCopy(MUSIC_SUBDIR);
1901 si->override_level_graphics = FALSE;
1902 si->override_level_sounds = FALSE;
1903 si->override_level_music = FALSE;
1905 si->editor.el_boulderdash = TRUE;
1906 si->editor.el_emerald_mine = TRUE;
1907 si->editor.el_more = TRUE;
1908 si->editor.el_sokoban = TRUE;
1909 si->editor.el_supaplex = TRUE;
1910 si->editor.el_diamond_caves = TRUE;
1911 si->editor.el_dx_boulderdash = TRUE;
1912 si->editor.el_chars = TRUE;
1913 si->editor.el_custom = TRUE;
1915 si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
1916 si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
1917 si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
1919 for (i=0; i<MAX_PLAYERS; i++)
1921 si->input[i].use_joystick = FALSE;
1922 si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
1923 si->input[i].joy.xleft = JOYSTICK_XLEFT;
1924 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1925 si->input[i].joy.xright = JOYSTICK_XRIGHT;
1926 si->input[i].joy.yupper = JOYSTICK_YUPPER;
1927 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1928 si->input[i].joy.ylower = JOYSTICK_YLOWER;
1929 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
1930 si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
1931 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
1932 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
1933 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
1934 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
1935 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
1936 si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED);
1939 si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
1940 si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
1942 si->options.verbose = FALSE;
1945 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
1949 if (!setup_file_hash)
1954 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1955 setSetupInfo(global_setup_tokens, i,
1956 getHashEntry(setup_file_hash, global_setup_tokens[i].text));
1961 for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
1962 setSetupInfo(editor_setup_tokens, i,
1963 getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
1966 /* shortcut setup */
1967 ssi = setup.shortcut;
1968 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1969 setSetupInfo(shortcut_setup_tokens, i,
1970 getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
1971 setup.shortcut = ssi;
1974 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1978 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1980 sii = setup.input[pnr];
1981 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1983 char full_token[100];
1985 sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
1986 setSetupInfo(player_setup_tokens, i,
1987 getHashEntry(setup_file_hash, full_token));
1989 setup.input[pnr] = sii;
1994 for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
1995 setSetupInfo(system_setup_tokens, i,
1996 getHashEntry(setup_file_hash, system_setup_tokens[i].text));
2000 soi = setup.options;
2001 for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
2002 setSetupInfo(options_setup_tokens, i,
2003 getHashEntry(setup_file_hash, options_setup_tokens[i].text));
2004 setup.options = soi;
2009 char *filename = getSetupFilename();
2010 SetupFileHash *setup_file_hash = NULL;
2012 /* always start with reliable default values */
2013 setSetupInfoToDefaults(&setup);
2015 setup_file_hash = loadSetupFileHash(filename);
2017 if (setup_file_hash)
2019 char *player_name_new;
2021 checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
2022 decodeSetupFileHash(setup_file_hash);
2024 setup.direct_draw = !setup.double_buffering;
2026 freeSetupFileHash(setup_file_hash);
2028 /* needed to work around problems with fixed length strings */
2029 player_name_new = get_corrected_login_name(setup.player_name);
2030 free(setup.player_name);
2031 setup.player_name = player_name_new;
2034 Error(ERR_WARN, "using default setup values");
2039 char *filename = getSetupFilename();
2043 InitUserDataDirectory();
2045 if (!(file = fopen(filename, MODE_WRITE)))
2047 Error(ERR_WARN, "cannot write setup file '%s'", filename);
2051 fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
2052 getCookie("SETUP")));
2053 fprintf(file, "\n");
2057 for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
2059 /* just to make things nicer :) */
2060 if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
2061 i == SETUP_TOKEN_GRAPHICS_SET)
2062 fprintf(file, "\n");
2064 fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
2069 fprintf(file, "\n");
2070 for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
2071 fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
2073 /* shortcut setup */
2074 ssi = setup.shortcut;
2075 fprintf(file, "\n");
2076 for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
2077 fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
2080 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
2084 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
2085 fprintf(file, "\n");
2087 sii = setup.input[pnr];
2088 for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
2089 fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
2094 fprintf(file, "\n");
2095 for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
2096 fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
2099 soi = setup.options;
2100 fprintf(file, "\n");
2101 for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
2102 fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
2106 SetFilePermissions(filename, PERMS_PRIVATE);
2109 void LoadCustomElementDescriptions()
2111 char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
2112 SetupFileHash *setup_file_hash;
2115 for (i=0; i<NUM_FILE_ELEMENTS; i++)
2117 if (element_info[i].custom_description != NULL)
2119 free(element_info[i].custom_description);
2120 element_info[i].custom_description = NULL;
2124 if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
2127 for (i=0; i<NUM_FILE_ELEMENTS; i++)
2129 char *token = getStringCat2(element_info[i].token_name, ".name");
2130 char *value = getHashEntry(setup_file_hash, token);
2133 element_info[i].custom_description = getStringCopy(value);
2138 freeSetupFileHash(setup_file_hash);
2141 void LoadSpecialMenuDesignSettings()
2143 char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
2144 SetupFileHash *setup_file_hash;
2147 /* always start with reliable default values from default config */
2148 for (i=0; image_config_vars[i].token != NULL; i++)
2149 for (j=0; image_config[j].token != NULL; j++)
2150 if (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
2151 *image_config_vars[i].value =
2152 get_integer_from_string(image_config[j].value);
2154 if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
2157 /* special case: initialize with default values that may be overwritten */
2158 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
2160 char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
2161 char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
2162 char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
2164 if (value_x != NULL)
2165 menu.draw_xoffset[i] = get_integer_from_string(value_x);
2166 if (value_y != NULL)
2167 menu.draw_yoffset[i] = get_integer_from_string(value_y);
2168 if (list_size != NULL)
2169 menu.list_size[i] = get_integer_from_string(list_size);
2172 /* read (and overwrite with) values that may be specified in config file */
2173 for (i=0; image_config_vars[i].token != NULL; i++)
2175 char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
2178 *image_config_vars[i].value = get_integer_from_string(value);
2181 freeSetupFileHash(setup_file_hash);