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 ***********************************************************/
19 #include "libgame/libgame.h"
27 #define CHUNK_ID_LEN 4 /* IFF style chunk id length */
28 #define CHUNK_SIZE_UNDEFINED 0 /* undefined chunk size == 0 */
29 #define CHUNK_SIZE_NONE -1 /* do not write chunk size */
30 #define FILE_VERS_CHUNK_SIZE 8 /* size of file version chunk */
31 #define LEVEL_HEADER_SIZE 80 /* size of level file header */
32 #define LEVEL_HEADER_UNUSED 13 /* unused level header bytes */
33 #define LEVEL_CHUNK_CNT2_SIZE 160 /* size of level CNT2 chunk */
34 #define LEVEL_CHUNK_CNT2_UNUSED 11 /* unused CNT2 chunk bytes */
35 #define LEVEL_CHUNK_CNT3_HEADER 16 /* size of level CNT3 header */
36 #define LEVEL_CHUNK_CNT3_UNUSED 10 /* unused CNT3 chunk bytes */
37 #define LEVEL_CPART_CUS3_SIZE 134 /* size of CUS3 chunk part */
38 #define LEVEL_CPART_CUS3_UNUSED 15 /* unused CUS3 bytes / part */
39 #define LEVEL_CHUNK_GRP1_SIZE 74 /* size of level GRP1 chunk */
40 #define TAPE_HEADER_SIZE 20 /* size of tape file header */
41 #define TAPE_HEADER_UNUSED 3 /* unused tape header bytes */
43 #define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x))
44 #define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
45 #define LEVEL_CHUNK_CUS4_SIZE(x) (48 + 48 + (x) * 48)
47 /* file identifier strings */
48 #define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
49 #define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
50 #define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
52 /* values for level file type identifier */
53 #define LEVEL_FILE_TYPE_UNKNOWN 0
54 #define LEVEL_FILE_TYPE_RND 1
55 #define LEVEL_FILE_TYPE_EM 2
57 #define LEVEL_FILE_TYPE_RND_PACKED (10 + LEVEL_FILE_TYPE_RND)
58 #define LEVEL_FILE_TYPE_EM_PACKED (10 + LEVEL_FILE_TYPE_EM)
60 #define IS_SINGLE_LEVEL_FILE(x) (x < 10)
61 #define IS_PACKED_LEVEL_FILE(x) (x > 10)
64 /* ========================================================================= */
65 /* level file functions */
66 /* ========================================================================= */
68 void setElementChangePages(struct ElementInfo *ei, int change_pages)
70 int change_page_size = sizeof(struct ElementChangeInfo);
72 ei->num_change_pages = MAX(1, change_pages);
75 checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
77 if (ei->current_change_page >= ei->num_change_pages)
78 ei->current_change_page = ei->num_change_pages - 1;
80 ei->change = &ei->change_page[ei->current_change_page];
83 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
87 change->can_change = FALSE;
89 change->events = CE_BITMASK_DEFAULT;
90 change->sides = CH_SIDE_ANY;
92 change->target_element = EL_EMPTY_SPACE;
94 change->delay_fixed = 0;
95 change->delay_random = 0;
96 change->delay_frames = 1;
98 change->trigger_element = EL_EMPTY_SPACE;
100 change->explode = FALSE;
101 change->use_content = FALSE;
102 change->only_complete = FALSE;
103 change->use_random_change = FALSE;
104 change->random = 100;
105 change->power = CP_NON_DESTRUCTIVE;
107 for (x = 0; x < 3; x++)
108 for (y = 0; y < 3; y++)
109 change->content[x][y] = EL_EMPTY_SPACE;
111 change->direct_action = 0;
112 change->other_action = 0;
114 change->pre_change_function = NULL;
115 change->change_function = NULL;
116 change->post_change_function = NULL;
119 static void setLevelInfoToDefaults(struct LevelInfo *level)
123 level->file_version = FILE_VERSION_ACTUAL;
124 level->game_version = GAME_VERSION_ACTUAL;
126 level->encoding_16bit_field = FALSE; /* default: only 8-bit elements */
127 level->encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
128 level->encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
130 level->fieldx = STD_LEV_FIELDX;
131 level->fieldy = STD_LEV_FIELDY;
133 for (x = 0; x < MAX_LEV_FIELDX; x++)
134 for (y = 0; y < MAX_LEV_FIELDY; y++)
135 level->field[x][y] = EL_SAND;
138 level->gems_needed = 0;
139 level->amoeba_speed = 10;
140 level->time_magic_wall = 10;
141 level->time_wheel = 10;
142 level->time_light = 10;
143 level->time_timegate = 10;
144 level->amoeba_content = EL_DIAMOND;
145 level->double_speed = FALSE;
146 level->initial_gravity = FALSE;
147 level->em_slippery_gems = FALSE;
149 level->use_custom_template = FALSE;
151 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
152 level->name[i] = '\0';
153 for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
154 level->author[i] = '\0';
156 strcpy(level->name, NAMELESS_LEVEL_NAME);
157 strcpy(level->author, ANONYMOUS_NAME);
159 for (i = 0; i < 4; i++)
161 level->envelope_text[i][0] = '\0';
162 level->envelope_xsize[i] = MAX_ENVELOPE_XSIZE;
163 level->envelope_ysize[i] = MAX_ENVELOPE_YSIZE;
166 for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
167 level->score[i] = 10;
169 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
170 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
171 for (x = 0; x < 3; x++)
172 for (y = 0; y < 3; y++)
173 level->yamyam_content[i][x][y] =
174 (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
176 level->field[0][0] = EL_PLAYER_1;
177 level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
179 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
183 setElementChangePages(&element_info[element], 1);
184 setElementChangeInfoToDefaults(element_info[element].change);
186 if (IS_CUSTOM_ELEMENT(element) || IS_GROUP_ELEMENT(element))
188 for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
189 element_info[element].description[j] = '\0';
191 if (element_info[element].custom_description != NULL)
192 strncpy(element_info[element].description,
193 element_info[element].custom_description,MAX_ELEMENT_NAME_LEN);
195 strcpy(element_info[element].description,
196 element_info[element].editor_description);
198 element_info[element].use_gfx_element = FALSE;
199 element_info[element].gfx_element = EL_EMPTY_SPACE;
202 if (IS_CUSTOM_ELEMENT(element))
204 element_info[element].collect_score = 10; /* special default */
205 element_info[element].collect_count = 1; /* special default */
207 element_info[element].push_delay_fixed = -1; /* initialize later */
208 element_info[element].push_delay_random = -1; /* initialize later */
209 element_info[element].move_delay_fixed = 0;
210 element_info[element].move_delay_random = 0;
212 element_info[element].move_pattern = MV_ALL_DIRECTIONS;
213 element_info[element].move_direction_initial = MV_AUTOMATIC;
214 element_info[element].move_stepsize = TILEX / 8;
215 element_info[element].move_enter_element = EL_EMPTY_SPACE;
216 element_info[element].move_leave_element = EL_EMPTY_SPACE;
217 element_info[element].move_leave_type = LEAVE_TYPE_UNLIMITED;
219 element_info[element].slippery_type = SLIPPERY_ANY_RANDOM;
221 for (x = 0; x < 3; x++)
222 for (y = 0; y < 3; y++)
223 element_info[element].content[x][y] = EL_EMPTY_SPACE;
225 element_info[element].access_type = 0;
226 element_info[element].access_layer = 0;
227 element_info[element].walk_to_action = 0;
228 element_info[element].smash_targets = 0;
229 element_info[element].deadliness = 0;
230 element_info[element].consistency = 0;
232 element_info[element].can_explode_by_fire = FALSE;
233 element_info[element].can_explode_smashed = FALSE;
234 element_info[element].can_explode_impact = FALSE;
236 element_info[element].current_change_page = 0;
238 /* start with no properties at all */
239 for (j = 0; j < NUM_EP_BITFIELDS; j++)
240 Properties[element][j] = EP_BITMASK_DEFAULT;
242 element_info[element].modified_settings = FALSE;
244 else if (IS_GROUP_ELEMENT(element) || element == EL_INTERNAL_EDITOR)
246 /* initialize memory for list of elements in group */
247 if (element_info[element].group == NULL)
248 element_info[element].group =
249 checked_malloc(sizeof(struct ElementGroupInfo));
251 for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
252 element_info[element].group->element[j] = EL_EMPTY_SPACE;
254 /* default: only one element in group */
255 element_info[element].group->num_elements = 1;
259 BorderElement = EL_STEELWALL;
261 level->no_level_file = FALSE;
263 if (leveldir_current == NULL) /* only when dumping level */
266 /* try to determine better author name than 'anonymous' */
267 if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
269 strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
270 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
274 switch (LEVELCLASS(leveldir_current))
276 case LEVELCLASS_TUTORIAL:
277 strcpy(level->author, PROGRAM_AUTHOR_STRING);
280 case LEVELCLASS_CONTRIB:
281 strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
282 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
285 case LEVELCLASS_PRIVATE:
286 strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
287 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
291 /* keep default value */
297 static void ActivateLevelTemplate()
299 /* Currently there is no special action needed to activate the template
300 data, because 'element_info' and 'Properties' overwrite the original
301 level data, while all other variables do not change. */
304 static char *getLevelFilenameFromBasename(char *basename)
306 static char *filename = NULL;
308 checked_free(filename);
310 filename = getPath2(getCurrentLevelDir(), basename);
315 static char *getSingleLevelBasename(int nr, int type)
317 static char basename[MAX_FILENAME_LEN];
321 case LEVEL_FILE_TYPE_RND:
323 sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
325 sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
328 case LEVEL_FILE_TYPE_EM:
329 sprintf(basename, "%d", nr);
333 strcpy(basename, UNDEFINED_FILENAME);
340 static char *getPackedLevelBasename(int type)
342 static char basename[MAX_FILENAME_LEN];
347 strcpy(basename, UNDEFINED_FILENAME);
354 static char *getSingleLevelFilename(int nr, int type)
356 return getLevelFilenameFromBasename(getSingleLevelBasename(nr, type));
359 static char *getPackedLevelFilename(int type)
361 return getLevelFilenameFromBasename(getPackedLevelBasename(type));
364 char *getDefaultLevelFilename(int nr)
366 return getSingleLevelFilename(nr, LEVEL_FILE_TYPE_RND);
369 static struct LevelFileInfo *getLevelFileInfo(int nr)
371 static struct LevelFileInfo level_file_info;
373 level_file_info.nr = nr;
375 /* special case: level template */
378 level_file_info.type = LEVEL_FILE_TYPE_RND;
379 level_file_info.filename = getDefaultLevelFilename(nr);
381 return &level_file_info;
384 /* 1st try: check for native Rocks'n'Diamonds level file */
385 level_file_info.type = LEVEL_FILE_TYPE_RND;
386 level_file_info.filename = getSingleLevelFilename(nr, level_file_info.type);
387 if (fileExists(level_file_info.filename))
388 return &level_file_info;
390 /* 2nd try: check for classic Emerald Mine level file */
391 level_file_info.type = LEVEL_FILE_TYPE_EM;
392 level_file_info.filename = getSingleLevelFilename(nr, level_file_info.type);
393 if (fileExists(level_file_info.filename))
394 return &level_file_info;
396 /* no known level file found -- use default values */
397 level_file_info.type = LEVEL_FILE_TYPE_RND;
398 level_file_info.filename = getSingleLevelFilename(nr, level_file_info.type);
400 return &level_file_info;
403 /* ------------------------------------------------------------------------- */
404 /* functions for loading R'n'D level */
405 /* ------------------------------------------------------------------------- */
407 static int checkLevelElement(int element)
409 /* map some (historic, now obsolete) elements */
414 case EL_PLAYER_OBSOLETE:
415 element = EL_PLAYER_1;
418 case EL_KEY_OBSOLETE:
421 case EL_EM_KEY_1_FILE_OBSOLETE:
422 element = EL_EM_KEY_1;
425 case EL_EM_KEY_2_FILE_OBSOLETE:
426 element = EL_EM_KEY_2;
429 case EL_EM_KEY_3_FILE_OBSOLETE:
430 element = EL_EM_KEY_3;
433 case EL_EM_KEY_4_FILE_OBSOLETE:
434 element = EL_EM_KEY_4;
437 case EL_ENVELOPE_OBSOLETE:
438 element = EL_ENVELOPE_1;
446 if (element >= NUM_FILE_ELEMENTS)
448 Error(ERR_WARN, "invalid level element %d", element);
450 element = EL_CHAR_QUESTION;
455 if (element >= NUM_FILE_ELEMENTS)
457 Error(ERR_WARN, "invalid level element %d", element);
459 element = EL_CHAR_QUESTION;
461 else if (element == EL_PLAYER_OBSOLETE)
462 element = EL_PLAYER_1;
463 else if (element == EL_KEY_OBSOLETE)
470 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
472 level->file_version = getFileVersion(file);
473 level->game_version = getFileVersion(file);
478 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
482 level->fieldx = getFile8Bit(file);
483 level->fieldy = getFile8Bit(file);
485 level->time = getFile16BitBE(file);
486 level->gems_needed = getFile16BitBE(file);
488 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
489 level->name[i] = getFile8Bit(file);
490 level->name[MAX_LEVEL_NAME_LEN] = 0;
492 for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
493 level->score[i] = getFile8Bit(file);
495 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
496 for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
497 for (y = 0; y < 3; y++)
498 for (x = 0; x < 3; x++)
499 level->yamyam_content[i][x][y] = checkLevelElement(getFile8Bit(file));
501 level->amoeba_speed = getFile8Bit(file);
502 level->time_magic_wall = getFile8Bit(file);
503 level->time_wheel = getFile8Bit(file);
504 level->amoeba_content = checkLevelElement(getFile8Bit(file));
505 level->double_speed = (getFile8Bit(file) == 1 ? TRUE : FALSE);
506 level->initial_gravity = (getFile8Bit(file) == 1 ? TRUE : FALSE);
507 level->encoding_16bit_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
508 level->em_slippery_gems = (getFile8Bit(file) == 1 ? TRUE : FALSE);
510 level->use_custom_template = (getFile8Bit(file) == 1 ? TRUE : FALSE);
512 ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
517 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
521 for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
522 level->author[i] = getFile8Bit(file);
523 level->author[MAX_LEVEL_NAME_LEN] = 0;
528 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
531 int chunk_size_expected = level->fieldx * level->fieldy;
533 /* Note: "chunk_size" was wrong before version 2.0 when elements are
534 stored with 16-bit encoding (and should be twice as big then).
535 Even worse, playfield data was stored 16-bit when only yamyam content
536 contained 16-bit elements and vice versa. */
538 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
539 chunk_size_expected *= 2;
541 if (chunk_size_expected != chunk_size)
543 ReadUnusedBytesFromFile(file, chunk_size);
544 return chunk_size_expected;
547 for (y = 0; y < level->fieldy; y++)
548 for (x = 0; x < level->fieldx; x++)
550 checkLevelElement(level->encoding_16bit_field ? getFile16BitBE(file) :
555 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
559 int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
560 int chunk_size_expected = header_size + content_size;
562 /* Note: "chunk_size" was wrong before version 2.0 when elements are
563 stored with 16-bit encoding (and should be twice as big then).
564 Even worse, playfield data was stored 16-bit when only yamyam content
565 contained 16-bit elements and vice versa. */
567 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
568 chunk_size_expected += content_size;
570 if (chunk_size_expected != chunk_size)
572 ReadUnusedBytesFromFile(file, chunk_size);
573 return chunk_size_expected;
577 level->num_yamyam_contents = getFile8Bit(file);
581 /* correct invalid number of content fields -- should never happen */
582 if (level->num_yamyam_contents < 1 ||
583 level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
584 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
586 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
587 for (y = 0; y < 3; y++)
588 for (x = 0; x < 3; x++)
589 level->yamyam_content[i][x][y] =
590 checkLevelElement(level->encoding_16bit_field ?
591 getFile16BitBE(file) : getFile8Bit(file));
595 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
599 int num_contents, content_xsize, content_ysize;
600 int content_array[MAX_ELEMENT_CONTENTS][3][3];
602 element = checkLevelElement(getFile16BitBE(file));
603 num_contents = getFile8Bit(file);
604 content_xsize = getFile8Bit(file);
605 content_ysize = getFile8Bit(file);
607 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
609 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
610 for (y = 0; y < 3; y++)
611 for (x = 0; x < 3; x++)
612 content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
614 /* correct invalid number of content fields -- should never happen */
615 if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
616 num_contents = STD_ELEMENT_CONTENTS;
618 if (element == EL_YAMYAM)
620 level->num_yamyam_contents = num_contents;
622 for (i = 0; i < num_contents; i++)
623 for (y = 0; y < 3; y++)
624 for (x = 0; x < 3; x++)
625 level->yamyam_content[i][x][y] = content_array[i][x][y];
627 else if (element == EL_BD_AMOEBA)
629 level->amoeba_content = content_array[0][0][0];
633 Error(ERR_WARN, "cannot load content for element '%d'", element);
639 static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
645 int chunk_size_expected;
647 element = checkLevelElement(getFile16BitBE(file));
648 if (!IS_ENVELOPE(element))
649 element = EL_ENVELOPE_1;
651 envelope_nr = element - EL_ENVELOPE_1;
653 envelope_len = getFile16BitBE(file);
655 level->envelope_xsize[envelope_nr] = getFile8Bit(file);
656 level->envelope_ysize[envelope_nr] = getFile8Bit(file);
658 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
660 chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
661 if (chunk_size_expected != chunk_size)
663 ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
664 return chunk_size_expected;
667 for (i = 0; i < envelope_len; i++)
668 level->envelope_text[envelope_nr][i] = getFile8Bit(file);
673 static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
675 int num_changed_custom_elements = getFile16BitBE(file);
676 int chunk_size_expected = 2 + num_changed_custom_elements * 6;
679 if (chunk_size_expected != chunk_size)
681 ReadUnusedBytesFromFile(file, chunk_size - 2);
682 return chunk_size_expected;
685 for (i = 0; i < num_changed_custom_elements; i++)
687 int element = getFile16BitBE(file);
688 int properties = getFile32BitBE(file);
690 if (IS_CUSTOM_ELEMENT(element))
691 Properties[element][EP_BITFIELD_BASE] = properties;
693 Error(ERR_WARN, "invalid custom element number %d", element);
699 static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
701 int num_changed_custom_elements = getFile16BitBE(file);
702 int chunk_size_expected = 2 + num_changed_custom_elements * 4;
705 if (chunk_size_expected != chunk_size)
707 ReadUnusedBytesFromFile(file, chunk_size - 2);
708 return chunk_size_expected;
711 for (i = 0; i < num_changed_custom_elements; i++)
713 int element = getFile16BitBE(file);
714 int custom_target_element = getFile16BitBE(file);
716 if (IS_CUSTOM_ELEMENT(element))
717 element_info[element].change->target_element = custom_target_element;
719 Error(ERR_WARN, "invalid custom element number %d", element);
725 static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
727 int num_changed_custom_elements = getFile16BitBE(file);
728 int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
731 if (chunk_size_expected != chunk_size)
733 ReadUnusedBytesFromFile(file, chunk_size - 2);
734 return chunk_size_expected;
737 for (i = 0; i < num_changed_custom_elements; i++)
739 int element = getFile16BitBE(file);
741 if (!IS_CUSTOM_ELEMENT(element))
743 Error(ERR_WARN, "invalid custom element number %d", element);
745 element = EL_INTERNAL_DUMMY;
748 for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
749 element_info[element].description[j] = getFile8Bit(file);
750 element_info[element].description[MAX_ELEMENT_NAME_LEN] = 0;
752 Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
754 /* some free bytes for future properties and padding */
755 ReadUnusedBytesFromFile(file, 7);
757 element_info[element].use_gfx_element = getFile8Bit(file);
758 element_info[element].gfx_element =
759 checkLevelElement(getFile16BitBE(file));
761 element_info[element].collect_score = getFile8Bit(file);
762 element_info[element].collect_count = getFile8Bit(file);
764 element_info[element].push_delay_fixed = getFile16BitBE(file);
765 element_info[element].push_delay_random = getFile16BitBE(file);
766 element_info[element].move_delay_fixed = getFile16BitBE(file);
767 element_info[element].move_delay_random = getFile16BitBE(file);
769 element_info[element].move_pattern = getFile16BitBE(file);
770 element_info[element].move_direction_initial = getFile8Bit(file);
771 element_info[element].move_stepsize = getFile8Bit(file);
773 for (y = 0; y < 3; y++)
774 for (x = 0; x < 3; x++)
775 element_info[element].content[x][y] =
776 checkLevelElement(getFile16BitBE(file));
778 element_info[element].change->events = getFile32BitBE(file);
780 element_info[element].change->target_element =
781 checkLevelElement(getFile16BitBE(file));
783 element_info[element].change->delay_fixed = getFile16BitBE(file);
784 element_info[element].change->delay_random = getFile16BitBE(file);
785 element_info[element].change->delay_frames = getFile16BitBE(file);
787 element_info[element].change->trigger_element =
788 checkLevelElement(getFile16BitBE(file));
790 element_info[element].change->explode = getFile8Bit(file);
791 element_info[element].change->use_content = getFile8Bit(file);
792 element_info[element].change->only_complete = getFile8Bit(file);
793 element_info[element].change->use_random_change = getFile8Bit(file);
795 element_info[element].change->random = getFile8Bit(file);
796 element_info[element].change->power = getFile8Bit(file);
798 for (y = 0; y < 3; y++)
799 for (x = 0; x < 3; x++)
800 element_info[element].change->content[x][y] =
801 checkLevelElement(getFile16BitBE(file));
803 element_info[element].slippery_type = getFile8Bit(file);
805 /* some free bytes for future properties and padding */
806 ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
808 /* mark that this custom element has been modified */
809 element_info[element].modified_settings = TRUE;
815 static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
817 struct ElementInfo *ei;
818 int chunk_size_expected;
822 element = getFile16BitBE(file);
824 if (!IS_CUSTOM_ELEMENT(element))
826 Error(ERR_WARN, "invalid custom element number %d", element);
828 ReadUnusedBytesFromFile(file, chunk_size - 2);
832 ei = &element_info[element];
834 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
835 ei->description[i] = getFile8Bit(file);
836 ei->description[MAX_ELEMENT_NAME_LEN] = 0;
838 Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
839 ReadUnusedBytesFromFile(file, 4); /* reserved for more base properties */
841 ei->num_change_pages = getFile8Bit(file);
843 /* some free bytes for future base property values and padding */
844 ReadUnusedBytesFromFile(file, 5);
846 chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
847 if (chunk_size_expected != chunk_size)
849 ReadUnusedBytesFromFile(file, chunk_size - 48);
850 return chunk_size_expected;
853 /* read custom property values */
855 ei->use_gfx_element = getFile8Bit(file);
856 ei->gfx_element = checkLevelElement(getFile16BitBE(file));
858 ei->collect_score = getFile8Bit(file);
859 ei->collect_count = getFile8Bit(file);
861 ei->push_delay_fixed = getFile16BitBE(file);
862 ei->push_delay_random = getFile16BitBE(file);
863 ei->move_delay_fixed = getFile16BitBE(file);
864 ei->move_delay_random = getFile16BitBE(file);
866 ei->move_pattern = getFile16BitBE(file);
867 ei->move_direction_initial = getFile8Bit(file);
868 ei->move_stepsize = getFile8Bit(file);
870 ei->slippery_type = getFile8Bit(file);
872 for (y = 0; y < 3; y++)
873 for (x = 0; x < 3; x++)
874 ei->content[x][y] = checkLevelElement(getFile16BitBE(file));
876 ei->move_enter_element = checkLevelElement(getFile16BitBE(file));
877 ei->move_leave_element = checkLevelElement(getFile16BitBE(file));
878 ei->move_leave_type = getFile8Bit(file);
880 /* some free bytes for future custom property values and padding */
881 ReadUnusedBytesFromFile(file, 7);
883 /* read change property values */
885 setElementChangePages(ei, ei->num_change_pages);
887 for (i = 0; i < ei->num_change_pages; i++)
889 struct ElementChangeInfo *change = &ei->change_page[i];
891 /* always start with reliable default values */
892 setElementChangeInfoToDefaults(change);
894 change->events = getFile32BitBE(file);
896 change->target_element = checkLevelElement(getFile16BitBE(file));
898 change->delay_fixed = getFile16BitBE(file);
899 change->delay_random = getFile16BitBE(file);
900 change->delay_frames = getFile16BitBE(file);
902 change->trigger_element = checkLevelElement(getFile16BitBE(file));
904 change->explode = getFile8Bit(file);
905 change->use_content = getFile8Bit(file);
906 change->only_complete = getFile8Bit(file);
907 change->use_random_change = getFile8Bit(file);
909 change->random = getFile8Bit(file);
910 change->power = getFile8Bit(file);
912 for (y = 0; y < 3; y++)
913 for (x = 0; x < 3; x++)
914 change->content[x][y] = checkLevelElement(getFile16BitBE(file));
916 change->can_change = getFile8Bit(file);
918 change->sides = getFile8Bit(file);
920 if (change->sides == CH_SIDE_NONE) /* correct empty sides field */
921 change->sides = CH_SIDE_ANY;
923 /* some free bytes for future change property values and padding */
924 ReadUnusedBytesFromFile(file, 8);
927 /* mark this custom element as modified */
928 ei->modified_settings = TRUE;
933 static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
935 struct ElementInfo *ei;
936 struct ElementGroupInfo *group;
940 element = getFile16BitBE(file);
942 if (!IS_GROUP_ELEMENT(element))
944 Error(ERR_WARN, "invalid group element number %d", element);
946 ReadUnusedBytesFromFile(file, chunk_size - 2);
950 ei = &element_info[element];
952 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
953 ei->description[i] = getFile8Bit(file);
954 ei->description[MAX_ELEMENT_NAME_LEN] = 0;
956 group = element_info[element].group;
958 group->num_elements = getFile8Bit(file);
960 ei->use_gfx_element = getFile8Bit(file);
961 ei->gfx_element = checkLevelElement(getFile16BitBE(file));
963 /* some free bytes for future values and padding */
964 ReadUnusedBytesFromFile(file, 4);
966 for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
967 group->element[i] = checkLevelElement(getFile16BitBE(file));
969 /* mark this group element as modified */
970 element_info[element].modified_settings = TRUE;
975 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
976 struct LevelFileInfo *level_file_info)
978 char *filename = level_file_info->filename;
979 char cookie[MAX_LINE_LEN];
980 char chunk_name[CHUNK_ID_LEN + 1];
984 /* always start with reliable default values */
985 setLevelInfoToDefaults(level);
987 if (!(file = fopen(filename, MODE_READ)))
989 level->no_level_file = TRUE;
991 if (level != &level_template)
992 Error(ERR_WARN, "cannot read level '%s' - using empty level", filename);
997 getFileChunkBE(file, chunk_name, NULL);
998 if (strcmp(chunk_name, "RND1") == 0)
1000 getFile32BitBE(file); /* not used */
1002 getFileChunkBE(file, chunk_name, NULL);
1003 if (strcmp(chunk_name, "CAVE") != 0)
1005 Error(ERR_WARN, "unknown format of level file '%s'", filename);
1010 else /* check for pre-2.0 file format with cookie string */
1012 strcpy(cookie, chunk_name);
1013 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
1014 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1015 cookie[strlen(cookie) - 1] = '\0';
1017 if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
1019 Error(ERR_WARN, "unknown format of level file '%s'", filename);
1024 if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
1026 Error(ERR_WARN, "unsupported version of level file '%s'", filename);
1031 /* pre-2.0 level files have no game version, so use file version here */
1032 level->game_version = level->file_version;
1035 if (level->file_version < FILE_VERSION_1_2)
1037 /* level files from versions before 1.2.0 without chunk structure */
1038 LoadLevel_HEAD(file, LEVEL_HEADER_SIZE, level);
1039 LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
1047 int (*loader)(FILE *, int, struct LevelInfo *);
1051 { "VERS", FILE_VERS_CHUNK_SIZE, LoadLevel_VERS },
1052 { "HEAD", LEVEL_HEADER_SIZE, LoadLevel_HEAD },
1053 { "AUTH", MAX_LEVEL_AUTHOR_LEN, LoadLevel_AUTH },
1054 { "BODY", -1, LoadLevel_BODY },
1055 { "CONT", -1, LoadLevel_CONT },
1056 { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
1057 { "CNT3", -1, LoadLevel_CNT3 },
1058 { "CUS1", -1, LoadLevel_CUS1 },
1059 { "CUS2", -1, LoadLevel_CUS2 },
1060 { "CUS3", -1, LoadLevel_CUS3 },
1061 { "CUS4", -1, LoadLevel_CUS4 },
1062 { "GRP1", -1, LoadLevel_GRP1 },
1066 while (getFileChunkBE(file, chunk_name, &chunk_size))
1070 while (chunk_info[i].name != NULL &&
1071 strcmp(chunk_name, chunk_info[i].name) != 0)
1074 if (chunk_info[i].name == NULL)
1076 Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
1077 chunk_name, filename);
1078 ReadUnusedBytesFromFile(file, chunk_size);
1080 else if (chunk_info[i].size != -1 &&
1081 chunk_info[i].size != chunk_size)
1083 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
1084 chunk_size, chunk_name, filename);
1085 ReadUnusedBytesFromFile(file, chunk_size);
1089 /* call function to load this level chunk */
1090 int chunk_size_expected =
1091 (chunk_info[i].loader)(file, chunk_size, level);
1093 /* the size of some chunks cannot be checked before reading other
1094 chunks first (like "HEAD" and "BODY") that contain some header
1095 information, so check them here */
1096 if (chunk_size_expected != chunk_size)
1098 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
1099 chunk_size, chunk_name, filename);
1108 /* ------------------------------------------------------------------------- */
1109 /* functions for loading EM level */
1110 /* ------------------------------------------------------------------------- */
1112 static int map_em_element_yam(int element)
1116 case 0x00: return EL_EMPTY;
1117 case 0x01: return EL_EMERALD;
1118 case 0x02: return EL_DIAMOND;
1119 case 0x03: return EL_ROCK;
1120 case 0x04: return EL_ROBOT;
1121 case 0x05: return EL_SPACESHIP_UP;
1122 case 0x06: return EL_BOMB;
1123 case 0x07: return EL_BUG_UP;
1124 case 0x08: return EL_AMOEBA_DROP;
1125 case 0x09: return EL_NUT;
1126 case 0x0a: return EL_YAMYAM;
1127 case 0x0b: return EL_QUICKSAND_FULL;
1128 case 0x0c: return EL_SAND;
1129 case 0x0d: return EL_WALL_SLIPPERY;
1130 case 0x0e: return EL_STEELWALL;
1131 case 0x0f: return EL_WALL;
1132 case 0x10: return EL_EM_KEY_1;
1133 case 0x11: return EL_EM_KEY_2;
1134 case 0x12: return EL_EM_KEY_4;
1135 case 0x13: return EL_EM_KEY_3;
1136 case 0x14: return EL_MAGIC_WALL;
1137 case 0x15: return EL_ROBOT_WHEEL;
1138 case 0x16: return EL_DYNAMITE;
1140 case 0x17: return EL_EM_KEY_1; /* EMC */
1141 case 0x18: return EL_BUG_UP; /* EMC */
1142 case 0x1a: return EL_DIAMOND; /* EMC */
1143 case 0x1b: return EL_EMERALD; /* EMC */
1144 case 0x25: return EL_NUT; /* EMC */
1145 case 0x80: return EL_EMPTY; /* EMC */
1146 case 0x85: return EL_EM_KEY_1; /* EMC */
1147 case 0x86: return EL_EM_KEY_2; /* EMC */
1148 case 0x87: return EL_EM_KEY_4; /* EMC */
1149 case 0x88: return EL_EM_KEY_3; /* EMC */
1150 case 0x94: return EL_QUICKSAND_EMPTY; /* EMC */
1151 case 0x9a: return EL_AMOEBA_WET; /* EMC */
1152 case 0xaf: return EL_DYNAMITE; /* EMC */
1153 case 0xbd: return EL_SAND; /* EMC */
1156 Error(ERR_WARN, "invalid level element %d", element);
1157 return EL_CHAR_QUESTION;
1161 static int map_em_element_field(int element)
1163 if (element >= 0xc8 && element <= 0xe1)
1164 return EL_CHAR_A + (element - 0xc8);
1165 else if (element >= 0xe2 && element <= 0xeb)
1166 return EL_CHAR_0 + (element - 0xe2);
1170 case 0x00: return EL_ROCK;
1171 case 0x02: return EL_DIAMOND;
1172 case 0x03: return EL_DIAMOND;
1173 case 0x04: return EL_ROBOT;
1174 case 0x05: return EL_ROBOT; /* EMC */
1175 case 0x08: return EL_SPACESHIP_UP;
1176 case 0x09: return EL_SPACESHIP_RIGHT;
1177 case 0x0a: return EL_SPACESHIP_DOWN;
1178 case 0x0b: return EL_SPACESHIP_LEFT;
1179 case 0x0c: return EL_SPACESHIP_UP;
1180 case 0x0d: return EL_SPACESHIP_RIGHT;
1181 case 0x0e: return EL_SPACESHIP_DOWN;
1182 case 0x0f: return EL_SPACESHIP_LEFT;
1183 case 0x10: return EL_BOMB;
1184 case 0x12: return EL_EMERALD;
1185 case 0x13: return EL_EMERALD;
1186 case 0x14: return EL_BUG_UP;
1187 case 0x15: return EL_BUG_RIGHT;
1188 case 0x16: return EL_BUG_DOWN;
1189 case 0x17: return EL_BUG_LEFT;
1190 case 0x18: return EL_BUG_UP;
1191 case 0x19: return EL_BUG_RIGHT;
1192 case 0x1a: return EL_BUG_DOWN;
1193 case 0x1b: return EL_BUG_LEFT;
1194 case 0x1c: return EL_AMOEBA_DROP;
1195 case 0x20: return EL_ROCK;
1196 case 0x24: return EL_MAGIC_WALL;
1197 case 0x25: return EL_NUT;
1199 /* looks like magic wheel, but is _always_ activated */
1200 case 0x28: return EL_ROBOT_WHEEL; /* EMC */
1202 case 0x29: return EL_YAMYAM;
1203 case 0x2a: return EL_YAMYAM;
1204 case 0x2b: return EL_YAMYAM; /* EMC */
1205 case 0x2c: return EL_YAMYAM; /* EMC */
1206 case 0x2d: return EL_QUICKSAND_FULL;
1207 case 0x39: return EL_EXPANDABLE_WALL_HORIZONTAL; /* EMC */
1208 case 0x3a: return EL_EXPANDABLE_WALL_VERTICAL; /* EMC */
1209 case 0x3b: return EL_DYNAMITE_ACTIVE;
1210 case 0x3c: return EL_DYNAMITE_ACTIVE;
1211 case 0x3d: return EL_DYNAMITE_ACTIVE;
1212 case 0x3e: return EL_DYNAMITE_ACTIVE;
1213 case 0x3f: return EL_ACID_POOL_BOTTOM;
1214 case 0x40: return EL_EXIT_OPEN;
1215 case 0x41: return EL_EXIT_OPEN;
1216 case 0x42: return EL_EXIT_OPEN;
1217 case 0x43: return EL_BALLOON;
1218 case 0x4e: return EL_INVISIBLE_WALL;
1219 case 0x65: return EL_ACID; /* EMC */
1220 case 0x73: return EL_SAND; /* EMC */
1221 case 0x74: return EL_STEELWALL;
1222 case 0x7b: return EL_ACID;
1223 case 0x80: return EL_EMPTY;
1224 case 0x81: return EL_WALL_SLIPPERY;
1225 case 0x82: return EL_SAND;
1226 case 0x83: return EL_STEELWALL;
1227 case 0x84: return EL_WALL;
1228 case 0x85: return EL_EM_KEY_1;
1229 case 0x86: return EL_EM_KEY_2;
1230 case 0x87: return EL_EM_KEY_4;
1231 case 0x88: return EL_EM_KEY_3;
1232 case 0x89: return EL_EM_GATE_1;
1233 case 0x8a: return EL_EM_GATE_2;
1234 case 0x8b: return EL_EM_GATE_4;
1235 case 0x8c: return EL_EM_GATE_3;
1236 case 0x8d: return EL_INVISIBLE_WALL; /* EMC */
1237 case 0x8e: return EL_EM_GATE_1_GRAY;
1238 case 0x8f: return EL_EM_GATE_2_GRAY;
1239 case 0x90: return EL_EM_GATE_4_GRAY;
1240 case 0x91: return EL_EM_GATE_3_GRAY;
1241 case 0x92: return EL_MAGIC_WALL;
1242 case 0x94: return EL_QUICKSAND_EMPTY;
1243 case 0x95: return EL_ACID_POOL_TOPLEFT;
1244 case 0x96: return EL_ACID_POOL_TOPRIGHT;
1245 case 0x97: return EL_ACID_POOL_BOTTOMLEFT;
1246 case 0x98: return EL_ACID_POOL_BOTTOMRIGHT;
1247 case 0x99: return EL_ACID;
1248 case 0x9a: return EL_AMOEBA_DEAD;
1249 case 0x9b: return EL_AMOEBA_DEAD;
1250 case 0x9c: return EL_AMOEBA_DEAD;
1251 case 0x9d: return EL_AMOEBA_DEAD;
1252 case 0x9e: return EL_EXIT_CLOSED;
1253 case 0x9f: return EL_CHAR_LESS; /* EMC */
1254 case 0x93: return EL_ROBOT_WHEEL;
1256 /* looks like normal dust, but behaves like wall */
1257 case 0xa0: return EL_WALL; /* EMC */
1259 case 0xa8: return EL_EMC_WALL_1; /* EMC */
1260 case 0xa9: return EL_EMC_WALL_2; /* EMC */
1261 case 0xaa: return EL_EMC_WALL_3; /* EMC */
1262 case 0xab: return EL_EMC_WALL_7; /* EMC */
1263 case 0xae: return EL_CHAR_MINUS; /* EMC */
1264 case 0xaf: return EL_DYNAMITE;
1265 case 0xb0: return EL_EMC_STEELWALL_1; /* EMC */
1266 case 0xb1: return EL_EMC_WALL_8; /* EMC */
1268 /* (exact steel wall) */
1269 case 0xb3: return EL_STEELWALL; /* EMC */
1271 case 0xb4: return EL_WALL_SLIPPERY; /* EMC */
1272 case 0xb5: return EL_EMC_WALL_6; /* EMC */
1273 case 0xb6: return EL_EMC_WALL_5; /* EMC */
1274 case 0xb7: return EL_EMC_WALL_4; /* EMC */
1275 case 0xb8: return EL_BALLOON_SWITCH_ANY; /* EMC */
1276 case 0xb9: return EL_BALLOON_SWITCH_RIGHT; /* EMC */
1277 case 0xba: return EL_BALLOON_SWITCH_DOWN; /* EMC */
1278 case 0xbb: return EL_BALLOON_SWITCH_LEFT; /* EMC */
1279 case 0xbc: return EL_BALLOON_SWITCH_UP; /* EMC */
1280 case 0xbd: return EL_SAND; /* EMC */
1281 case 0xec: return EL_CHAR_PERIOD;
1282 case 0xed: return EL_CHAR_EXCLAM;
1283 case 0xee: return EL_CHAR_COLON;
1284 case 0xef: return EL_CHAR_QUESTION;
1285 case 0xf0: return EL_CHAR_GREATER;
1286 case 0xf1: return EL_CHAR_COPYRIGHT;
1287 case 0xfe: return EL_PLAYER_1;
1288 case 0xff: return EL_PLAYER_2;
1291 Error(ERR_WARN, "invalid level element %d", element);
1292 return EL_CHAR_QUESTION;
1296 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
1297 struct LevelFileInfo *level_file_info)
1299 char *filename = level_file_info->filename;
1301 unsigned char body[40][64];
1302 unsigned char *leveldata = &body[0][0];
1303 unsigned char *header = &leveldata[2048];
1304 unsigned char code0 = 0x65;
1305 unsigned char code1 = 0x11;
1306 boolean level_is_crypted = FALSE;
1307 int nr = level_file_info->nr;
1311 /* always start with reliable default values */
1312 setLevelInfoToDefaults(level);
1314 if (!(file = fopen(filename, MODE_READ)))
1316 level->no_level_file = TRUE;
1318 Error(ERR_WARN, "cannot read level '%s' - using empty level", filename);
1323 for(i = 0; i < 2106; i++)
1324 leveldata[i] = fgetc(file);
1328 /* check if level data is crypted by testing against known starting bytes
1329 of the few existing crypted level files (from Emerald Mine 1 + 2) */
1331 if ((leveldata[0] == 0xf1 ||
1332 leveldata[0] == 0xf5) && leveldata[2] == 0xe7 && leveldata[3] == 0xee)
1334 level_is_crypted = TRUE;
1336 if (leveldata[0] == 0xf5) /* error in crypted Emerald Mine 2 levels */
1337 leveldata[0] = 0xf1;
1340 if (level_is_crypted) /* decode crypted level data */
1342 for(i = 0; i < 2106; i++)
1344 leveldata[i] ^= code0;
1345 leveldata[i] -= code1;
1347 code0 = (code0 + 7) & 0xff;
1354 level->time = header[46] * 10;
1355 level->gems_needed = header[47];
1357 /* The original Emerald Mine levels have their level number stored
1358 at the second byte of the level file...
1359 Do not trust this information at other level files, e.g. EMC,
1360 but correct it anyway (normally the first row is completely
1361 steel wall, so the correction does not hurt anyway). */
1363 if (leveldata[1] == nr)
1364 leveldata[1] = leveldata[2]; /* correct level number field */
1366 sprintf(level->name, "Level %d", nr);
1368 level->score[SC_EMERALD] = header[36];
1369 level->score[SC_DIAMOND] = header[37];
1370 level->score[SC_ROBOT] = header[38];
1371 level->score[SC_SPACESHIP] = header[39];
1372 level->score[SC_BUG] = header[40];
1373 level->score[SC_YAMYAM] = header[41];
1374 level->score[SC_NUT] = header[42];
1375 level->score[SC_DYNAMITE] = header[43];
1376 level->score[SC_TIME_BONUS] = header[44];
1378 level->num_yamyam_contents = 4;
1380 for(i = 0; i < level->num_yamyam_contents; i++)
1381 for(y = 0; y < 3; y++)
1382 for(x = 0; x < 3; x++)
1383 level->yamyam_content[i][x][y] =
1384 map_em_element_yam(header[i * 9 + y * 3 + x]);
1386 level->amoeba_speed = (header[52] * 256 + header[53]) % 256;
1387 level->time_magic_wall = (header[54] * 256 + header[55]) * 16 / 100;
1388 level->time_wheel = (header[56] * 256 + header[57]) * 16 / 100;
1389 level->amoeba_content = EL_DIAMOND;
1391 for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
1393 int new_element = map_em_element_field(body[y][x]);
1395 if (new_element == EL_AMOEBA_DEAD && level->amoeba_speed)
1396 new_element = EL_AMOEBA_WET;
1398 level->field[x][y] = new_element;
1401 jx = (header[48] * 256 + header[49]) % 64;
1402 jy = (header[48] * 256 + header[49]) / 64;
1403 level->field[jx][jy] = EL_PLAYER_1;
1405 jx = (header[50] * 256 + header[51]) % 64;
1406 jy = (header[50] * 256 + header[51]) / 64;
1407 level->field[jx][jy] = EL_PLAYER_2;
1410 void LoadLevelFromFileInfo(struct LevelInfo *level,
1411 struct LevelFileInfo *level_file_info)
1413 switch (level_file_info->type)
1415 case LEVEL_FILE_TYPE_RND:
1416 LoadLevelFromFileInfo_RND(level, level_file_info);
1419 case LEVEL_FILE_TYPE_EM:
1420 LoadLevelFromFileInfo_EM(level, level_file_info);
1424 LoadLevelFromFileInfo_RND(level, level_file_info);
1429 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
1431 static struct LevelFileInfo level_file_info;
1433 level_file_info.nr = 0; /* unknown */
1434 level_file_info.type = LEVEL_FILE_TYPE_RND; /* no others supported yet */
1435 level_file_info.filename = filename;
1437 LoadLevelFromFileInfo(level, &level_file_info);
1440 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
1442 if (leveldir_current == NULL) /* only when dumping level */
1446 printf("::: sort_priority: %d\n", leveldir_current->sort_priority);
1449 /* determine correct game engine version of current level */
1451 if (!leveldir_current->latest_engine)
1453 if (IS_LEVELCLASS_CONTRIB(leveldir_current) ||
1454 IS_LEVELCLASS_PRIVATE(leveldir_current) ||
1455 IS_LEVELCLASS_UNDEFINED(leveldir_current))
1459 printf("\n::: This level is private or contributed: '%s'\n", filename);
1463 printf("\n::: Use the stored game engine version for this level\n");
1466 /* For all levels which are not forced to use the latest game engine
1467 version (normally user contributed, private and undefined levels),
1468 use the version of the game engine the levels were created for.
1470 Since 2.0.1, the game engine version is now directly stored
1471 in the level file (chunk "VERS"), so there is no need anymore
1472 to set the game version from the file version (except for old,
1473 pre-2.0 levels, where the game version is still taken from the
1474 file format version used to store the level -- see above). */
1476 /* do some special adjustments to support older level versions */
1477 if (level->file_version == FILE_VERSION_1_0)
1479 Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
1480 Error(ERR_WARN, "using high speed movement for player");
1482 /* player was faster than monsters in (pre-)1.0 levels */
1483 level->double_speed = TRUE;
1486 /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
1487 if (level->game_version == VERSION_IDENT(2,0,1,0))
1488 level->em_slippery_gems = TRUE;
1493 printf("\n::: ALWAYS USE LATEST ENGINE FOR THIS LEVEL: [%d] '%s'\n",
1494 leveldir_current->sort_priority, filename);
1498 printf("\n::: Use latest game engine version for this level.\n");
1501 /* For all levels which are forced to use the latest game engine version
1502 (normally all but user contributed, private and undefined levels), set
1503 the game engine version to the actual version; this allows for actual
1504 corrections in the game engine to take effect for existing, converted
1505 levels (from "classic" or other existing games) to make the emulation
1506 of the corresponding game more accurate, while (hopefully) not breaking
1507 existing levels created from other players. */
1510 printf("::: changing engine from %d to %d\n",
1511 level->game_version, GAME_VERSION_ACTUAL);
1514 level->game_version = GAME_VERSION_ACTUAL;
1516 /* Set special EM style gems behaviour: EM style gems slip down from
1517 normal, steel and growing wall. As this is a more fundamental change,
1518 it seems better to set the default behaviour to "off" (as it is more
1519 natural) and make it configurable in the level editor (as a property
1520 of gem style elements). Already existing converted levels (neither
1521 private nor contributed levels) are changed to the new behaviour. */
1523 if (level->file_version < FILE_VERSION_2_0)
1524 level->em_slippery_gems = TRUE;
1528 printf("::: => %d\n", level->game_version);
1532 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
1536 /* map custom element change events that have changed in newer versions
1537 (these following values were accidentally changed in version 3.0.1) */
1538 if (level->game_version <= VERSION_IDENT(3,0,0,0))
1540 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1542 int element = EL_CUSTOM_START + i;
1544 /* order of checking and copying events to be mapped is important */
1545 for (j = CE_BY_OTHER_ACTION; j >= CE_BY_PLAYER_OBSOLETE; j--)
1547 if (HAS_CHANGE_EVENT(element, j - 2))
1549 SET_CHANGE_EVENT(element, j - 2, FALSE);
1550 SET_CHANGE_EVENT(element, j, TRUE);
1554 /* order of checking and copying events to be mapped is important */
1555 for (j = CE_OTHER_GETS_COLLECTED; j >= CE_HITTING_SOMETHING; j--)
1557 if (HAS_CHANGE_EVENT(element, j - 1))
1559 SET_CHANGE_EVENT(element, j - 1, FALSE);
1560 SET_CHANGE_EVENT(element, j, TRUE);
1566 /* some custom element change events get mapped since version 3.0.3 */
1567 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1569 int element = EL_CUSTOM_START + i;
1571 if (HAS_CHANGE_EVENT(element, CE_BY_PLAYER_OBSOLETE) ||
1572 HAS_CHANGE_EVENT(element, CE_BY_COLLISION_OBSOLETE))
1574 SET_CHANGE_EVENT(element, CE_BY_PLAYER_OBSOLETE, FALSE);
1575 SET_CHANGE_EVENT(element, CE_BY_COLLISION_OBSOLETE, FALSE);
1577 SET_CHANGE_EVENT(element, CE_BY_DIRECT_ACTION, TRUE);
1581 /* initialize "can_change" field for old levels with only one change page */
1582 if (level->game_version <= VERSION_IDENT(3,0,2,0))
1584 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1586 int element = EL_CUSTOM_START + i;
1588 if (CAN_CHANGE(element))
1589 element_info[element].change->can_change = TRUE;
1594 /* set default push delay values (corrected since version 3.0.7-1) */
1595 if (level->game_version < VERSION_IDENT(3,0,7,1))
1597 game.default_push_delay_fixed = 2;
1598 game.default_push_delay_random = 8;
1602 game.default_push_delay_fixed = 8;
1603 game.default_push_delay_random = 8;
1606 /* set uninitialized push delay values of custom elements in older levels */
1607 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1609 int element = EL_CUSTOM_START + i;
1611 if (element_info[element].push_delay_fixed == -1)
1612 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
1613 if (element_info[element].push_delay_random == -1)
1614 element_info[element].push_delay_random = game.default_push_delay_random;
1618 /* initialize element properties for level editor etc. */
1619 InitElementPropertiesEngine(level->game_version);
1622 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
1626 /* map elements that have changed in newer versions */
1627 for (y = 0; y < level->fieldy; y++)
1629 for (x = 0; x < level->fieldx; x++)
1631 int element = level->field[x][y];
1633 if (level->game_version <= VERSION_IDENT(2,2,0,0))
1635 /* map game font elements */
1636 element = (element == EL_CHAR('[') ? EL_CHAR_AUMLAUT :
1637 element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
1638 element == EL_CHAR(']') ? EL_CHAR_UUMLAUT :
1639 element == EL_CHAR('^') ? EL_CHAR_COPYRIGHT : element);
1642 if (level->game_version < VERSION_IDENT(3,0,0,0))
1644 /* map Supaplex gravity tube elements */
1645 element = (element == EL_SP_GRAVITY_PORT_LEFT ? EL_SP_PORT_LEFT :
1646 element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
1647 element == EL_SP_GRAVITY_PORT_UP ? EL_SP_PORT_UP :
1648 element == EL_SP_GRAVITY_PORT_DOWN ? EL_SP_PORT_DOWN :
1652 level->field[x][y] = element;
1656 /* copy elements to runtime playfield array */
1657 for (x = 0; x < MAX_LEV_FIELDX; x++)
1658 for (y = 0; y < MAX_LEV_FIELDY; y++)
1659 Feld[x][y] = level->field[x][y];
1661 /* initialize level size variables for faster access */
1662 lev_fieldx = level->fieldx;
1663 lev_fieldy = level->fieldy;
1665 /* determine border element for this level */
1669 void LoadLevelTemplate(int nr)
1672 struct LevelFileInfo *level_file_info = getLevelFileInfo(nr);
1673 char *filename = level_file_info->filename;
1675 LoadLevelFromFileInfo(&level_template, level_file_info);
1677 char *filename = getDefaultLevelFilename(nr);
1679 LoadLevelFromFilename_RND(&level_template, filename);
1682 LoadLevel_InitVersion(&level, filename);
1683 LoadLevel_InitElements(&level, filename);
1685 ActivateLevelTemplate();
1688 void LoadLevel(int nr)
1691 struct LevelFileInfo *level_file_info = getLevelFileInfo(nr);
1692 char *filename = level_file_info->filename;
1694 LoadLevelFromFileInfo(&level, level_file_info);
1696 char *filename = getLevelFilename(nr);
1698 LoadLevelFromFilename_RND(&level, filename);
1701 if (level.use_custom_template)
1702 LoadLevelTemplate(-1);
1705 LoadLevel_InitVersion(&level, filename);
1706 LoadLevel_InitElements(&level, filename);
1707 LoadLevel_InitPlayfield(&level, filename);
1709 LoadLevel_InitLevel(&level, filename);
1713 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
1715 putFileVersion(file, level->file_version);
1716 putFileVersion(file, level->game_version);
1719 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
1723 putFile8Bit(file, level->fieldx);
1724 putFile8Bit(file, level->fieldy);
1726 putFile16BitBE(file, level->time);
1727 putFile16BitBE(file, level->gems_needed);
1729 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
1730 putFile8Bit(file, level->name[i]);
1732 for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
1733 putFile8Bit(file, level->score[i]);
1735 for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
1736 for (y = 0; y < 3; y++)
1737 for (x = 0; x < 3; x++)
1738 putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
1739 level->yamyam_content[i][x][y]));
1740 putFile8Bit(file, level->amoeba_speed);
1741 putFile8Bit(file, level->time_magic_wall);
1742 putFile8Bit(file, level->time_wheel);
1743 putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
1744 level->amoeba_content));
1745 putFile8Bit(file, (level->double_speed ? 1 : 0));
1746 putFile8Bit(file, (level->initial_gravity ? 1 : 0));
1747 putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
1748 putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
1750 putFile8Bit(file, (level->use_custom_template ? 1 : 0));
1752 WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
1755 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
1759 for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
1760 putFile8Bit(file, level->author[i]);
1763 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
1767 for (y = 0; y < level->fieldy; y++)
1768 for (x = 0; x < level->fieldx; x++)
1769 if (level->encoding_16bit_field)
1770 putFile16BitBE(file, level->field[x][y]);
1772 putFile8Bit(file, level->field[x][y]);
1776 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
1780 putFile8Bit(file, EL_YAMYAM);
1781 putFile8Bit(file, level->num_yamyam_contents);
1782 putFile8Bit(file, 0);
1783 putFile8Bit(file, 0);
1785 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1786 for (y = 0; y < 3; y++)
1787 for (x = 0; x < 3; x++)
1788 if (level->encoding_16bit_field)
1789 putFile16BitBE(file, level->yamyam_content[i][x][y]);
1791 putFile8Bit(file, level->yamyam_content[i][x][y]);
1795 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
1798 int num_contents, content_xsize, content_ysize;
1799 int content_array[MAX_ELEMENT_CONTENTS][3][3];
1801 if (element == EL_YAMYAM)
1803 num_contents = level->num_yamyam_contents;
1807 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1808 for (y = 0; y < 3; y++)
1809 for (x = 0; x < 3; x++)
1810 content_array[i][x][y] = level->yamyam_content[i][x][y];
1812 else if (element == EL_BD_AMOEBA)
1818 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1819 for (y = 0; y < 3; y++)
1820 for (x = 0; x < 3; x++)
1821 content_array[i][x][y] = EL_EMPTY;
1822 content_array[0][0][0] = level->amoeba_content;
1826 /* chunk header already written -- write empty chunk data */
1827 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
1829 Error(ERR_WARN, "cannot save content for element '%d'", element);
1833 putFile16BitBE(file, element);
1834 putFile8Bit(file, num_contents);
1835 putFile8Bit(file, content_xsize);
1836 putFile8Bit(file, content_ysize);
1838 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
1840 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1841 for (y = 0; y < 3; y++)
1842 for (x = 0; x < 3; x++)
1843 putFile16BitBE(file, content_array[i][x][y]);
1846 static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
1849 int envelope_nr = element - EL_ENVELOPE_1;
1850 int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
1852 putFile16BitBE(file, element);
1853 putFile16BitBE(file, envelope_len);
1854 putFile8Bit(file, level->envelope_xsize[envelope_nr]);
1855 putFile8Bit(file, level->envelope_ysize[envelope_nr]);
1857 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
1859 for (i = 0; i < envelope_len; i++)
1860 putFile8Bit(file, level->envelope_text[envelope_nr][i]);
1864 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
1865 int num_changed_custom_elements)
1869 putFile16BitBE(file, num_changed_custom_elements);
1871 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1873 int element = EL_CUSTOM_START + i;
1875 if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
1877 if (check < num_changed_custom_elements)
1879 putFile16BitBE(file, element);
1880 putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
1887 if (check != num_changed_custom_elements) /* should not happen */
1888 Error(ERR_WARN, "inconsistent number of custom element properties");
1893 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
1894 int num_changed_custom_elements)
1898 putFile16BitBE(file, num_changed_custom_elements);
1900 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1902 int element = EL_CUSTOM_START + i;
1904 if (element_info[element].change->target_element != EL_EMPTY_SPACE)
1906 if (check < num_changed_custom_elements)
1908 putFile16BitBE(file, element);
1909 putFile16BitBE(file, element_info[element].change->target_element);
1916 if (check != num_changed_custom_elements) /* should not happen */
1917 Error(ERR_WARN, "inconsistent number of custom target elements");
1922 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
1923 int num_changed_custom_elements)
1925 int i, j, x, y, check = 0;
1927 putFile16BitBE(file, num_changed_custom_elements);
1929 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1931 int element = EL_CUSTOM_START + i;
1933 if (element_info[element].modified_settings)
1935 if (check < num_changed_custom_elements)
1937 putFile16BitBE(file, element);
1939 for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
1940 putFile8Bit(file, element_info[element].description[j]);
1942 putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
1944 /* some free bytes for future properties and padding */
1945 WriteUnusedBytesToFile(file, 7);
1947 putFile8Bit(file, element_info[element].use_gfx_element);
1948 putFile16BitBE(file, element_info[element].gfx_element);
1950 putFile8Bit(file, element_info[element].collect_score);
1951 putFile8Bit(file, element_info[element].collect_count);
1953 putFile16BitBE(file, element_info[element].push_delay_fixed);
1954 putFile16BitBE(file, element_info[element].push_delay_random);
1955 putFile16BitBE(file, element_info[element].move_delay_fixed);
1956 putFile16BitBE(file, element_info[element].move_delay_random);
1958 putFile16BitBE(file, element_info[element].move_pattern);
1959 putFile8Bit(file, element_info[element].move_direction_initial);
1960 putFile8Bit(file, element_info[element].move_stepsize);
1962 for (y = 0; y < 3; y++)
1963 for (x = 0; x < 3; x++)
1964 putFile16BitBE(file, element_info[element].content[x][y]);
1966 putFile32BitBE(file, element_info[element].change->events);
1968 putFile16BitBE(file, element_info[element].change->target_element);
1970 putFile16BitBE(file, element_info[element].change->delay_fixed);
1971 putFile16BitBE(file, element_info[element].change->delay_random);
1972 putFile16BitBE(file, element_info[element].change->delay_frames);
1974 putFile16BitBE(file, element_info[element].change->trigger_element);
1976 putFile8Bit(file, element_info[element].change->explode);
1977 putFile8Bit(file, element_info[element].change->use_content);
1978 putFile8Bit(file, element_info[element].change->only_complete);
1979 putFile8Bit(file, element_info[element].change->use_random_change);
1981 putFile8Bit(file, element_info[element].change->random);
1982 putFile8Bit(file, element_info[element].change->power);
1984 for (y = 0; y < 3; y++)
1985 for (x = 0; x < 3; x++)
1986 putFile16BitBE(file, element_info[element].change->content[x][y]);
1988 putFile8Bit(file, element_info[element].slippery_type);
1990 /* some free bytes for future properties and padding */
1991 WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
1998 if (check != num_changed_custom_elements) /* should not happen */
1999 Error(ERR_WARN, "inconsistent number of custom element properties");
2003 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
2005 struct ElementInfo *ei = &element_info[element];
2008 putFile16BitBE(file, element);
2010 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2011 putFile8Bit(file, ei->description[i]);
2013 putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
2014 WriteUnusedBytesToFile(file, 4); /* reserved for more base properties */
2016 putFile8Bit(file, ei->num_change_pages);
2018 /* some free bytes for future base property values and padding */
2019 WriteUnusedBytesToFile(file, 5);
2021 /* write custom property values */
2023 putFile8Bit(file, ei->use_gfx_element);
2024 putFile16BitBE(file, ei->gfx_element);
2026 putFile8Bit(file, ei->collect_score);
2027 putFile8Bit(file, ei->collect_count);
2029 putFile16BitBE(file, ei->push_delay_fixed);
2030 putFile16BitBE(file, ei->push_delay_random);
2031 putFile16BitBE(file, ei->move_delay_fixed);
2032 putFile16BitBE(file, ei->move_delay_random);
2034 putFile16BitBE(file, ei->move_pattern);
2035 putFile8Bit(file, ei->move_direction_initial);
2036 putFile8Bit(file, ei->move_stepsize);
2038 putFile8Bit(file, ei->slippery_type);
2040 for (y = 0; y < 3; y++)
2041 for (x = 0; x < 3; x++)
2042 putFile16BitBE(file, ei->content[x][y]);
2044 putFile16BitBE(file, ei->move_enter_element);
2045 putFile16BitBE(file, ei->move_leave_element);
2046 putFile8Bit(file, ei->move_leave_type);
2048 /* some free bytes for future custom property values and padding */
2049 WriteUnusedBytesToFile(file, 7);
2051 /* write change property values */
2053 for (i = 0; i < ei->num_change_pages; i++)
2055 struct ElementChangeInfo *change = &ei->change_page[i];
2057 putFile32BitBE(file, change->events);
2059 putFile16BitBE(file, change->target_element);
2061 putFile16BitBE(file, change->delay_fixed);
2062 putFile16BitBE(file, change->delay_random);
2063 putFile16BitBE(file, change->delay_frames);
2065 putFile16BitBE(file, change->trigger_element);
2067 putFile8Bit(file, change->explode);
2068 putFile8Bit(file, change->use_content);
2069 putFile8Bit(file, change->only_complete);
2070 putFile8Bit(file, change->use_random_change);
2072 putFile8Bit(file, change->random);
2073 putFile8Bit(file, change->power);
2075 for (y = 0; y < 3; y++)
2076 for (x = 0; x < 3; x++)
2077 putFile16BitBE(file, change->content[x][y]);
2079 putFile8Bit(file, change->can_change);
2081 putFile8Bit(file, change->sides);
2083 /* some free bytes for future change property values and padding */
2084 WriteUnusedBytesToFile(file, 8);
2088 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
2090 struct ElementInfo *ei = &element_info[element];
2091 struct ElementGroupInfo *group = ei->group;
2094 putFile16BitBE(file, element);
2096 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2097 putFile8Bit(file, ei->description[i]);
2099 putFile8Bit(file, group->num_elements);
2101 putFile8Bit(file, ei->use_gfx_element);
2102 putFile16BitBE(file, ei->gfx_element);
2104 /* some free bytes for future values and padding */
2105 WriteUnusedBytesToFile(file, 4);
2107 for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
2108 putFile16BitBE(file, group->element[i]);
2111 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
2113 int body_chunk_size;
2117 if (!(file = fopen(filename, MODE_WRITE)))
2119 Error(ERR_WARN, "cannot save level file '%s'", filename);
2123 level->file_version = FILE_VERSION_ACTUAL;
2124 level->game_version = GAME_VERSION_ACTUAL;
2126 /* check level field for 16-bit elements */
2127 level->encoding_16bit_field = FALSE;
2128 for (y = 0; y < level->fieldy; y++)
2129 for (x = 0; x < level->fieldx; x++)
2130 if (level->field[x][y] > 255)
2131 level->encoding_16bit_field = TRUE;
2133 /* check yamyam content for 16-bit elements */
2134 level->encoding_16bit_yamyam = FALSE;
2135 for (i = 0; i < level->num_yamyam_contents; i++)
2136 for (y = 0; y < 3; y++)
2137 for (x = 0; x < 3; x++)
2138 if (level->yamyam_content[i][x][y] > 255)
2139 level->encoding_16bit_yamyam = TRUE;
2141 /* check amoeba content for 16-bit elements */
2142 level->encoding_16bit_amoeba = FALSE;
2143 if (level->amoeba_content > 255)
2144 level->encoding_16bit_amoeba = TRUE;
2146 /* calculate size of "BODY" chunk */
2148 level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
2150 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
2151 putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
2153 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
2154 SaveLevel_VERS(file, level);
2156 putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
2157 SaveLevel_HEAD(file, level);
2159 putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
2160 SaveLevel_AUTH(file, level);
2162 putFileChunkBE(file, "BODY", body_chunk_size);
2163 SaveLevel_BODY(file, level);
2165 if (level->encoding_16bit_yamyam ||
2166 level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
2168 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
2169 SaveLevel_CNT2(file, level, EL_YAMYAM);
2172 if (level->encoding_16bit_amoeba)
2174 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
2175 SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
2178 /* check for envelope content */
2179 for (i = 0; i < 4; i++)
2181 if (strlen(level->envelope_text[i]) > 0)
2183 int envelope_len = strlen(level->envelope_text[i]) + 1;
2185 putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_SIZE(envelope_len));
2186 SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
2190 /* check for non-default custom elements (unless using template level) */
2191 if (!level->use_custom_template)
2193 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
2195 int element = EL_CUSTOM_START + i;
2197 if (element_info[element].modified_settings)
2199 int num_change_pages = element_info[element].num_change_pages;
2201 putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages));
2202 SaveLevel_CUS4(file, level, element);
2207 /* check for non-default group elements (unless using template level) */
2208 if (!level->use_custom_template)
2210 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
2212 int element = EL_GROUP_START + i;
2214 if (element_info[element].modified_settings)
2216 putFileChunkBE(file, "GRP1", LEVEL_CHUNK_GRP1_SIZE);
2217 SaveLevel_GRP1(file, level, element);
2224 SetFilePermissions(filename, PERMS_PRIVATE);
2227 void SaveLevel(int nr)
2229 char *filename = getDefaultLevelFilename(nr);
2231 SaveLevelFromFilename(&level, filename);
2234 void SaveLevelTemplate()
2236 char *filename = getDefaultLevelFilename(-1);
2238 SaveLevelFromFilename(&level, filename);
2241 void DumpLevel(struct LevelInfo *level)
2243 printf_line("-", 79);
2244 printf("Level xxx (file version %08d, game version %08d)\n",
2245 level->file_version, level->game_version);
2246 printf_line("-", 79);
2248 printf("Level Author: '%s'\n", level->author);
2249 printf("Level Title: '%s'\n", level->name);
2251 printf("Playfield Size: %d x %d\n", level->fieldx, level->fieldy);
2253 printf("Level Time: %d seconds\n", level->time);
2254 printf("Gems needed: %d\n", level->gems_needed);
2256 printf("Time for Magic Wall: %d seconds\n", level->time_magic_wall);
2257 printf("Time for Wheel: %d seconds\n", level->time_wheel);
2258 printf("Time for Light: %d seconds\n", level->time_light);
2259 printf("Time for Timegate: %d seconds\n", level->time_timegate);
2261 printf("Amoeba Speed: %d\n", level->amoeba_speed);
2263 printf("Gravity: %s\n", (level->initial_gravity ? "yes" : "no"));
2264 printf("Double Speed Movement: %s\n", (level->double_speed ? "yes" : "no"));
2265 printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
2267 printf_line("-", 79);
2271 /* ========================================================================= */
2272 /* tape file functions */
2273 /* ========================================================================= */
2275 static void setTapeInfoToDefaults()
2279 /* always start with reliable default values (empty tape) */
2282 /* default values (also for pre-1.2 tapes) with only the first player */
2283 tape.player_participates[0] = TRUE;
2284 for (i = 1; i < MAX_PLAYERS; i++)
2285 tape.player_participates[i] = FALSE;
2287 /* at least one (default: the first) player participates in every tape */
2288 tape.num_participating_players = 1;
2290 tape.level_nr = level_nr;
2292 tape.changed = FALSE;
2294 tape.recording = FALSE;
2295 tape.playing = FALSE;
2296 tape.pausing = FALSE;
2299 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
2301 tape->file_version = getFileVersion(file);
2302 tape->game_version = getFileVersion(file);
2307 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
2311 tape->random_seed = getFile32BitBE(file);
2312 tape->date = getFile32BitBE(file);
2313 tape->length = getFile32BitBE(file);
2315 /* read header fields that are new since version 1.2 */
2316 if (tape->file_version >= FILE_VERSION_1_2)
2318 byte store_participating_players = getFile8Bit(file);
2321 /* since version 1.2, tapes store which players participate in the tape */
2322 tape->num_participating_players = 0;
2323 for (i = 0; i < MAX_PLAYERS; i++)
2325 tape->player_participates[i] = FALSE;
2327 if (store_participating_players & (1 << i))
2329 tape->player_participates[i] = TRUE;
2330 tape->num_participating_players++;
2334 ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
2336 engine_version = getFileVersion(file);
2337 if (engine_version > 0)
2338 tape->engine_version = engine_version;
2340 tape->engine_version = tape->game_version;
2346 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
2348 int level_identifier_size;
2351 level_identifier_size = getFile16BitBE(file);
2353 tape->level_identifier =
2354 checked_realloc(tape->level_identifier, level_identifier_size);
2356 for (i = 0; i < level_identifier_size; i++)
2357 tape->level_identifier[i] = getFile8Bit(file);
2359 tape->level_nr = getFile16BitBE(file);
2361 chunk_size = 2 + level_identifier_size + 2;
2366 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
2369 int chunk_size_expected =
2370 (tape->num_participating_players + 1) * tape->length;
2372 if (chunk_size_expected != chunk_size)
2374 ReadUnusedBytesFromFile(file, chunk_size);
2375 return chunk_size_expected;
2378 for (i = 0; i < tape->length; i++)
2380 if (i >= MAX_TAPELEN)
2383 for (j = 0; j < MAX_PLAYERS; j++)
2385 tape->pos[i].action[j] = MV_NO_MOVING;
2387 if (tape->player_participates[j])
2388 tape->pos[i].action[j] = getFile8Bit(file);
2391 tape->pos[i].delay = getFile8Bit(file);
2393 if (tape->file_version == FILE_VERSION_1_0)
2395 /* eliminate possible diagonal moves in old tapes */
2396 /* this is only for backward compatibility */
2398 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
2399 byte action = tape->pos[i].action[0];
2400 int k, num_moves = 0;
2402 for (k = 0; k<4; k++)
2404 if (action & joy_dir[k])
2406 tape->pos[i + num_moves].action[0] = joy_dir[k];
2408 tape->pos[i + num_moves].delay = 0;
2417 tape->length += num_moves;
2420 else if (tape->file_version < FILE_VERSION_2_0)
2422 /* convert pre-2.0 tapes to new tape format */
2424 if (tape->pos[i].delay > 1)
2427 tape->pos[i + 1] = tape->pos[i];
2428 tape->pos[i + 1].delay = 1;
2431 for (j = 0; j < MAX_PLAYERS; j++)
2432 tape->pos[i].action[j] = MV_NO_MOVING;
2433 tape->pos[i].delay--;
2444 if (i != tape->length)
2445 chunk_size = (tape->num_participating_players + 1) * i;
2450 void LoadTapeFromFilename(char *filename)
2452 char cookie[MAX_LINE_LEN];
2453 char chunk_name[CHUNK_ID_LEN + 1];
2457 /* always start with reliable default values */
2458 setTapeInfoToDefaults();
2460 if (!(file = fopen(filename, MODE_READ)))
2463 getFileChunkBE(file, chunk_name, NULL);
2464 if (strcmp(chunk_name, "RND1") == 0)
2466 getFile32BitBE(file); /* not used */
2468 getFileChunkBE(file, chunk_name, NULL);
2469 if (strcmp(chunk_name, "TAPE") != 0)
2471 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
2476 else /* check for pre-2.0 file format with cookie string */
2478 strcpy(cookie, chunk_name);
2479 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
2480 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
2481 cookie[strlen(cookie) - 1] = '\0';
2483 if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
2485 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
2490 if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
2492 Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
2497 /* pre-2.0 tape files have no game version, so use file version here */
2498 tape.game_version = tape.file_version;
2501 if (tape.file_version < FILE_VERSION_1_2)
2503 /* tape files from versions before 1.2.0 without chunk structure */
2504 LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
2505 LoadTape_BODY(file, 2 * tape.length, &tape);
2513 int (*loader)(FILE *, int, struct TapeInfo *);
2517 { "VERS", FILE_VERS_CHUNK_SIZE, LoadTape_VERS },
2518 { "HEAD", TAPE_HEADER_SIZE, LoadTape_HEAD },
2519 { "INFO", -1, LoadTape_INFO },
2520 { "BODY", -1, LoadTape_BODY },
2524 while (getFileChunkBE(file, chunk_name, &chunk_size))
2528 while (chunk_info[i].name != NULL &&
2529 strcmp(chunk_name, chunk_info[i].name) != 0)
2532 if (chunk_info[i].name == NULL)
2534 Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
2535 chunk_name, filename);
2536 ReadUnusedBytesFromFile(file, chunk_size);
2538 else if (chunk_info[i].size != -1 &&
2539 chunk_info[i].size != chunk_size)
2541 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
2542 chunk_size, chunk_name, filename);
2543 ReadUnusedBytesFromFile(file, chunk_size);
2547 /* call function to load this tape chunk */
2548 int chunk_size_expected =
2549 (chunk_info[i].loader)(file, chunk_size, &tape);
2551 /* the size of some chunks cannot be checked before reading other
2552 chunks first (like "HEAD" and "BODY") that contain some header
2553 information, so check them here */
2554 if (chunk_size_expected != chunk_size)
2556 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
2557 chunk_size, chunk_name, filename);
2565 tape.length_seconds = GetTapeLength();
2568 printf("::: tape game version: %d\n", tape.game_version);
2569 printf("::: tape engine version: %d\n", tape.engine_version);
2573 void LoadTape(int nr)
2575 char *filename = getTapeFilename(nr);
2577 LoadTapeFromFilename(filename);
2580 void LoadSolutionTape(int nr)
2582 char *filename = getSolutionTapeFilename(nr);
2584 LoadTapeFromFilename(filename);
2587 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
2589 putFileVersion(file, tape->file_version);
2590 putFileVersion(file, tape->game_version);
2593 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
2596 byte store_participating_players = 0;
2598 /* set bits for participating players for compact storage */
2599 for (i = 0; i < MAX_PLAYERS; i++)
2600 if (tape->player_participates[i])
2601 store_participating_players |= (1 << i);
2603 putFile32BitBE(file, tape->random_seed);
2604 putFile32BitBE(file, tape->date);
2605 putFile32BitBE(file, tape->length);
2607 putFile8Bit(file, store_participating_players);
2609 /* unused bytes not at the end here for 4-byte alignment of engine_version */
2610 WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
2612 putFileVersion(file, tape->engine_version);
2615 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
2617 int level_identifier_size = strlen(tape->level_identifier) + 1;
2620 putFile16BitBE(file, level_identifier_size);
2622 for (i = 0; i < level_identifier_size; i++)
2623 putFile8Bit(file, tape->level_identifier[i]);
2625 putFile16BitBE(file, tape->level_nr);
2628 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
2632 for (i = 0; i < tape->length; i++)
2634 for (j = 0; j < MAX_PLAYERS; j++)
2635 if (tape->player_participates[j])
2636 putFile8Bit(file, tape->pos[i].action[j]);
2638 putFile8Bit(file, tape->pos[i].delay);
2642 void SaveTape(int nr)
2644 char *filename = getTapeFilename(nr);
2646 boolean new_tape = TRUE;
2647 int num_participating_players = 0;
2648 int info_chunk_size;
2649 int body_chunk_size;
2652 InitTapeDirectory(leveldir_current->filename);
2654 /* if a tape still exists, ask to overwrite it */
2655 if (access(filename, F_OK) == 0)
2658 if (!Request("Replace old tape ?", REQ_ASK))
2662 if (!(file = fopen(filename, MODE_WRITE)))
2664 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
2668 tape.file_version = FILE_VERSION_ACTUAL;
2669 tape.game_version = GAME_VERSION_ACTUAL;
2671 /* count number of participating players */
2672 for (i = 0; i < MAX_PLAYERS; i++)
2673 if (tape.player_participates[i])
2674 num_participating_players++;
2676 info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
2677 body_chunk_size = (num_participating_players + 1) * tape.length;
2679 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
2680 putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
2682 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
2683 SaveTape_VERS(file, &tape);
2685 putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
2686 SaveTape_HEAD(file, &tape);
2688 putFileChunkBE(file, "INFO", info_chunk_size);
2689 SaveTape_INFO(file, &tape);
2691 putFileChunkBE(file, "BODY", body_chunk_size);
2692 SaveTape_BODY(file, &tape);
2696 SetFilePermissions(filename, PERMS_PRIVATE);
2698 tape.changed = FALSE;
2701 Request("tape saved !", REQ_CONFIRM);
2704 void DumpTape(struct TapeInfo *tape)
2708 if (TAPE_IS_EMPTY(*tape))
2710 Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
2714 printf_line("-", 79);
2715 printf("Tape of Level %03d (file version %08d, game version %08d)\n",
2716 tape->level_nr, tape->file_version, tape->game_version);
2717 printf("Level series identifier: '%s'\n", tape->level_identifier);
2718 printf_line("-", 79);
2720 for (i = 0; i < tape->length; i++)
2722 if (i >= MAX_TAPELEN)
2725 printf("%03d: ", i);
2727 for (j = 0; j < MAX_PLAYERS; j++)
2729 if (tape->player_participates[j])
2731 int action = tape->pos[i].action[j];
2733 printf("%d:%02x ", j, action);
2734 printf("[%c%c%c%c|%c%c] - ",
2735 (action & JOY_LEFT ? '<' : ' '),
2736 (action & JOY_RIGHT ? '>' : ' '),
2737 (action & JOY_UP ? '^' : ' '),
2738 (action & JOY_DOWN ? 'v' : ' '),
2739 (action & JOY_BUTTON_1 ? '1' : ' '),
2740 (action & JOY_BUTTON_2 ? '2' : ' '));
2744 printf("(%03d)\n", tape->pos[i].delay);
2747 printf_line("-", 79);
2751 /* ========================================================================= */
2752 /* score file functions */
2753 /* ========================================================================= */
2755 void LoadScore(int nr)
2758 char *filename = getScoreFilename(nr);
2759 char cookie[MAX_LINE_LEN];
2760 char line[MAX_LINE_LEN];
2764 /* always start with reliable default values */
2765 for (i = 0; i < MAX_SCORE_ENTRIES; i++)
2767 strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
2768 highscore[i].Score = 0;
2771 if (!(file = fopen(filename, MODE_READ)))
2774 /* check file identifier */
2775 fgets(cookie, MAX_LINE_LEN, file);
2776 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
2777 cookie[strlen(cookie) - 1] = '\0';
2779 if (!checkCookieString(cookie, SCORE_COOKIE))
2781 Error(ERR_WARN, "unknown format of score file '%s'", filename);
2786 for (i = 0; i < MAX_SCORE_ENTRIES; i++)
2788 fscanf(file, "%d", &highscore[i].Score);
2789 fgets(line, MAX_LINE_LEN, file);
2791 if (line[strlen(line) - 1] == '\n')
2792 line[strlen(line) - 1] = '\0';
2794 for (line_ptr = line; *line_ptr; line_ptr++)
2796 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
2798 strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
2799 highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
2808 void SaveScore(int nr)
2811 char *filename = getScoreFilename(nr);
2814 InitScoreDirectory(leveldir_current->filename);
2816 if (!(file = fopen(filename, MODE_WRITE)))
2818 Error(ERR_WARN, "cannot save score for level %d", nr);
2822 fprintf(file, "%s\n\n", SCORE_COOKIE);
2824 for (i = 0; i < MAX_SCORE_ENTRIES; i++)
2825 fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
2829 SetFilePermissions(filename, PERMS_PUBLIC);
2833 /* ========================================================================= */
2834 /* setup file functions */
2835 /* ========================================================================= */
2837 #define TOKEN_STR_PLAYER_PREFIX "player_"
2840 #define SETUP_TOKEN_PLAYER_NAME 0
2841 #define SETUP_TOKEN_SOUND 1
2842 #define SETUP_TOKEN_SOUND_LOOPS 2
2843 #define SETUP_TOKEN_SOUND_MUSIC 3
2844 #define SETUP_TOKEN_SOUND_SIMPLE 4
2845 #define SETUP_TOKEN_TOONS 5
2846 #define SETUP_TOKEN_SCROLL_DELAY 6
2847 #define SETUP_TOKEN_SOFT_SCROLLING 7
2848 #define SETUP_TOKEN_FADING 8
2849 #define SETUP_TOKEN_AUTORECORD 9
2850 #define SETUP_TOKEN_QUICK_DOORS 10
2851 #define SETUP_TOKEN_TEAM_MODE 11
2852 #define SETUP_TOKEN_HANDICAP 12
2853 #define SETUP_TOKEN_TIME_LIMIT 13
2854 #define SETUP_TOKEN_FULLSCREEN 14
2855 #define SETUP_TOKEN_ASK_ON_ESCAPE 15
2856 #define SETUP_TOKEN_GRAPHICS_SET 16
2857 #define SETUP_TOKEN_SOUNDS_SET 17
2858 #define SETUP_TOKEN_MUSIC_SET 18
2859 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 19
2860 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 20
2861 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 21
2863 #define NUM_GLOBAL_SETUP_TOKENS 22
2866 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH 0
2867 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE 1
2868 #define SETUP_TOKEN_EDITOR_EL_MORE 2
2869 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN 3
2870 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX 4
2871 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES 5
2872 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH 6
2873 #define SETUP_TOKEN_EDITOR_EL_CHARS 7
2874 #define SETUP_TOKEN_EDITOR_EL_CUSTOM 8
2875 #define SETUP_TOKEN_EDITOR_EL_CUSTOM_MORE 9
2876 #define SETUP_TOKEN_EDITOR_EL_HEADLINES 10
2877 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED 11
2879 #define NUM_EDITOR_SETUP_TOKENS 12
2881 /* shortcut setup */
2882 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0
2883 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME 1
2884 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE 2
2886 #define NUM_SHORTCUT_SETUP_TOKENS 3
2889 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK 0
2890 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME 1
2891 #define SETUP_TOKEN_PLAYER_JOY_XLEFT 2
2892 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE 3
2893 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT 4
2894 #define SETUP_TOKEN_PLAYER_JOY_YUPPER 5
2895 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE 6
2896 #define SETUP_TOKEN_PLAYER_JOY_YLOWER 7
2897 #define SETUP_TOKEN_PLAYER_JOY_SNAP 8
2898 #define SETUP_TOKEN_PLAYER_JOY_DROP 9
2899 #define SETUP_TOKEN_PLAYER_KEY_LEFT 10
2900 #define SETUP_TOKEN_PLAYER_KEY_RIGHT 11
2901 #define SETUP_TOKEN_PLAYER_KEY_UP 12
2902 #define SETUP_TOKEN_PLAYER_KEY_DOWN 13
2903 #define SETUP_TOKEN_PLAYER_KEY_SNAP 14
2904 #define SETUP_TOKEN_PLAYER_KEY_DROP 15
2906 #define NUM_PLAYER_SETUP_TOKENS 16
2909 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER 0
2910 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 1
2912 #define NUM_SYSTEM_SETUP_TOKENS 2
2915 #define SETUP_TOKEN_OPTIONS_VERBOSE 0
2917 #define NUM_OPTIONS_SETUP_TOKENS 1
2920 static struct SetupInfo si;
2921 static struct SetupEditorInfo sei;
2922 static struct SetupShortcutInfo ssi;
2923 static struct SetupInputInfo sii;
2924 static struct SetupSystemInfo syi;
2925 static struct OptionInfo soi;
2927 static struct TokenInfo global_setup_tokens[] =
2929 { TYPE_STRING, &si.player_name, "player_name" },
2930 { TYPE_SWITCH, &si.sound, "sound" },
2931 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
2932 { TYPE_SWITCH, &si.sound_music, "background_music" },
2933 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
2934 { TYPE_SWITCH, &si.toons, "toons" },
2935 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
2936 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
2937 { TYPE_SWITCH, &si.fading, "screen_fading" },
2938 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
2939 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
2940 { TYPE_SWITCH, &si.team_mode, "team_mode" },
2941 { TYPE_SWITCH, &si.handicap, "handicap" },
2942 { TYPE_SWITCH, &si.time_limit, "time_limit" },
2943 { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
2944 { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
2945 { TYPE_STRING, &si.graphics_set, "graphics_set" },
2946 { TYPE_STRING, &si.sounds_set, "sounds_set" },
2947 { TYPE_STRING, &si.music_set, "music_set" },
2948 { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
2949 { TYPE_SWITCH, &si.override_level_sounds, "override_level_sounds" },
2950 { TYPE_SWITCH, &si.override_level_music, "override_level_music" },
2953 static struct TokenInfo editor_setup_tokens[] =
2955 { TYPE_SWITCH, &sei.el_boulderdash, "editor.el_boulderdash" },
2956 { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine" },
2957 { TYPE_SWITCH, &sei.el_more, "editor.el_more" },
2958 { TYPE_SWITCH, &sei.el_sokoban, "editor.el_sokoban" },
2959 { TYPE_SWITCH, &sei.el_supaplex, "editor.el_supaplex" },
2960 { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves" },
2961 { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash" },
2962 { TYPE_SWITCH, &sei.el_chars, "editor.el_chars" },
2963 { TYPE_SWITCH, &sei.el_custom, "editor.el_custom" },
2964 { TYPE_SWITCH, &sei.el_custom_more, "editor.el_custom_more" },
2965 { TYPE_SWITCH, &sei.el_headlines, "editor.el_headlines" },
2966 { TYPE_SWITCH, &sei.el_user_defined, "editor.el_user_defined" },
2969 static struct TokenInfo shortcut_setup_tokens[] =
2971 { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
2972 { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
2973 { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }
2976 static struct TokenInfo player_setup_tokens[] =
2978 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
2979 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
2980 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
2981 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
2982 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
2983 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
2984 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
2985 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
2986 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
2987 { TYPE_INTEGER, &sii.joy.drop, ".joy.place_bomb" },
2988 { TYPE_KEY_X11, &sii.key.left, ".key.move_left" },
2989 { TYPE_KEY_X11, &sii.key.right, ".key.move_right" },
2990 { TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
2991 { TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
2992 { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
2993 { TYPE_KEY_X11, &sii.key.drop, ".key.place_bomb" }
2996 static struct TokenInfo system_setup_tokens[] =
2998 { TYPE_STRING, &syi.sdl_audiodriver, "system.sdl_audiodriver" },
2999 { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }
3002 static struct TokenInfo options_setup_tokens[] =
3004 { TYPE_BOOLEAN, &soi.verbose, "options.verbose" }
3007 static char *get_corrected_login_name(char *login_name)
3009 /* needed because player name must be a fixed length string */
3010 char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
3012 strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
3013 login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
3015 if (strlen(login_name) > MAX_PLAYER_NAME_LEN) /* name has been cut */
3016 if (strchr(login_name_new, ' '))
3017 *strchr(login_name_new, ' ') = '\0';
3019 return login_name_new;
3022 static void setSetupInfoToDefaults(struct SetupInfo *si)
3026 si->player_name = get_corrected_login_name(getLoginName());
3029 si->sound_loops = TRUE;
3030 si->sound_music = TRUE;
3031 si->sound_simple = TRUE;
3033 si->double_buffering = TRUE;
3034 si->direct_draw = !si->double_buffering;
3035 si->scroll_delay = TRUE;
3036 si->soft_scrolling = TRUE;
3038 si->autorecord = TRUE;
3039 si->quick_doors = FALSE;
3040 si->team_mode = FALSE;
3041 si->handicap = TRUE;
3042 si->time_limit = TRUE;
3043 si->fullscreen = FALSE;
3044 si->ask_on_escape = TRUE;
3046 si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
3047 si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
3048 si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
3049 si->override_level_graphics = FALSE;
3050 si->override_level_sounds = FALSE;
3051 si->override_level_music = FALSE;
3053 si->editor.el_boulderdash = TRUE;
3054 si->editor.el_emerald_mine = TRUE;
3055 si->editor.el_more = TRUE;
3056 si->editor.el_sokoban = TRUE;
3057 si->editor.el_supaplex = TRUE;
3058 si->editor.el_diamond_caves = TRUE;
3059 si->editor.el_dx_boulderdash = TRUE;
3060 si->editor.el_chars = TRUE;
3061 si->editor.el_custom = TRUE;
3062 si->editor.el_custom_more = FALSE;
3064 si->editor.el_headlines = TRUE;
3065 si->editor.el_user_defined = FALSE;
3067 si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
3068 si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
3069 si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
3071 for (i = 0; i < MAX_PLAYERS; i++)
3073 si->input[i].use_joystick = FALSE;
3074 si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
3075 si->input[i].joy.xleft = JOYSTICK_XLEFT;
3076 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
3077 si->input[i].joy.xright = JOYSTICK_XRIGHT;
3078 si->input[i].joy.yupper = JOYSTICK_YUPPER;
3079 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
3080 si->input[i].joy.ylower = JOYSTICK_YLOWER;
3081 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
3082 si->input[i].joy.drop = (i == 0 ? JOY_BUTTON_2 : 0);
3083 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
3084 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
3085 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
3086 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
3087 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
3088 si->input[i].key.drop = (i == 0 ? DEFAULT_KEY_DROP : KSYM_UNDEFINED);
3091 si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
3092 si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
3094 si->options.verbose = FALSE;
3097 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
3101 if (!setup_file_hash)
3106 for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
3107 setSetupInfo(global_setup_tokens, i,
3108 getHashEntry(setup_file_hash, global_setup_tokens[i].text));
3113 for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
3114 setSetupInfo(editor_setup_tokens, i,
3115 getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
3118 /* shortcut setup */
3119 ssi = setup.shortcut;
3120 for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
3121 setSetupInfo(shortcut_setup_tokens, i,
3122 getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
3123 setup.shortcut = ssi;
3126 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
3130 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
3132 sii = setup.input[pnr];
3133 for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
3135 char full_token[100];
3137 sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
3138 setSetupInfo(player_setup_tokens, i,
3139 getHashEntry(setup_file_hash, full_token));
3141 setup.input[pnr] = sii;
3146 for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
3147 setSetupInfo(system_setup_tokens, i,
3148 getHashEntry(setup_file_hash, system_setup_tokens[i].text));
3152 soi = setup.options;
3153 for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
3154 setSetupInfo(options_setup_tokens, i,
3155 getHashEntry(setup_file_hash, options_setup_tokens[i].text));
3156 setup.options = soi;
3161 char *filename = getSetupFilename();
3162 SetupFileHash *setup_file_hash = NULL;
3164 /* always start with reliable default values */
3165 setSetupInfoToDefaults(&setup);
3167 setup_file_hash = loadSetupFileHash(filename);
3169 if (setup_file_hash)
3171 char *player_name_new;
3173 checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
3174 decodeSetupFileHash(setup_file_hash);
3176 setup.direct_draw = !setup.double_buffering;
3178 freeSetupFileHash(setup_file_hash);
3180 /* needed to work around problems with fixed length strings */
3181 player_name_new = get_corrected_login_name(setup.player_name);
3182 free(setup.player_name);
3183 setup.player_name = player_name_new;
3186 Error(ERR_WARN, "using default setup values");
3191 char *filename = getSetupFilename();
3195 InitUserDataDirectory();
3197 if (!(file = fopen(filename, MODE_WRITE)))
3199 Error(ERR_WARN, "cannot write setup file '%s'", filename);
3203 fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
3204 getCookie("SETUP")));
3205 fprintf(file, "\n");
3209 for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
3211 /* just to make things nicer :) */
3212 if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
3213 i == SETUP_TOKEN_GRAPHICS_SET)
3214 fprintf(file, "\n");
3216 fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
3221 fprintf(file, "\n");
3222 for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
3223 fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
3225 /* shortcut setup */
3226 ssi = setup.shortcut;
3227 fprintf(file, "\n");
3228 for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
3229 fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
3232 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
3236 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
3237 fprintf(file, "\n");
3239 sii = setup.input[pnr];
3240 for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
3241 fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
3246 fprintf(file, "\n");
3247 for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
3248 fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
3251 soi = setup.options;
3252 fprintf(file, "\n");
3253 for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
3254 fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
3258 SetFilePermissions(filename, PERMS_PRIVATE);
3261 void LoadCustomElementDescriptions()
3263 char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
3264 SetupFileHash *setup_file_hash;
3267 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
3269 if (element_info[i].custom_description != NULL)
3271 free(element_info[i].custom_description);
3272 element_info[i].custom_description = NULL;
3276 if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
3279 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
3281 char *token = getStringCat2(element_info[i].token_name, ".name");
3282 char *value = getHashEntry(setup_file_hash, token);
3285 element_info[i].custom_description = getStringCopy(value);
3290 freeSetupFileHash(setup_file_hash);
3293 void LoadSpecialMenuDesignSettings()
3295 char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
3296 SetupFileHash *setup_file_hash;
3299 /* always start with reliable default values from default config */
3300 for (i = 0; image_config_vars[i].token != NULL; i++)
3301 for (j = 0; image_config[j].token != NULL; j++)
3302 if (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
3303 *image_config_vars[i].value =
3304 get_auto_parameter_value(image_config_vars[i].token,
3305 image_config[j].value);
3307 if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
3310 /* special case: initialize with default values that may be overwritten */
3311 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
3313 char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
3314 char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
3315 char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
3317 if (value_x != NULL)
3318 menu.draw_xoffset[i] = get_integer_from_string(value_x);
3319 if (value_y != NULL)
3320 menu.draw_yoffset[i] = get_integer_from_string(value_y);
3321 if (list_size != NULL)
3322 menu.list_size[i] = get_integer_from_string(list_size);
3325 /* read (and overwrite with) values that may be specified in config file */
3326 for (i = 0; image_config_vars[i].token != NULL; i++)
3328 char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
3331 *image_config_vars[i].value =
3332 get_auto_parameter_value(image_config_vars[i].token, value);
3335 freeSetupFileHash(setup_file_hash);
3338 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
3340 char *filename = getEditorSetupFilename();
3341 SetupFileList *setup_file_list, *list;
3342 SetupFileHash *element_hash;
3343 int num_unknown_tokens = 0;
3346 if ((setup_file_list = loadSetupFileList(filename)) == NULL)
3349 element_hash = newSetupFileHash();
3351 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
3352 setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
3354 /* determined size may be larger than needed (due to unknown elements) */
3356 for (list = setup_file_list; list != NULL; list = list->next)
3359 /* add space for up to 3 more elements for padding that may be needed */
3362 *elements = checked_malloc(*num_elements * sizeof(int));
3365 for (list = setup_file_list; list != NULL; list = list->next)
3367 char *value = getHashEntry(element_hash, list->token);
3371 (*elements)[(*num_elements)++] = atoi(value);
3375 if (num_unknown_tokens == 0)
3377 Error(ERR_RETURN_LINE, "-");
3378 Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
3379 Error(ERR_RETURN, "- config file: '%s'", filename);
3381 num_unknown_tokens++;
3384 Error(ERR_RETURN, "- token: '%s'", list->token);
3388 if (num_unknown_tokens > 0)
3389 Error(ERR_RETURN_LINE, "-");
3391 while (*num_elements % 4) /* pad with empty elements, if needed */
3392 (*elements)[(*num_elements)++] = EL_EMPTY;
3394 freeSetupFileList(setup_file_list);
3395 freeSetupFileHash(element_hash);
3399 for (i = 0; i < *num_elements; i++)
3400 printf("editor: element '%s' [%d]\n",
3401 element_info[(*elements)[i]].token_name, (*elements)[i]);
3405 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
3408 SetupFileHash *setup_file_hash = NULL;
3409 struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
3410 char *filename_music, *filename_prefix, *filename_info;
3416 token_to_value_ptr[] =
3418 { "title_header", &tmp_music_file_info.title_header },
3419 { "artist_header", &tmp_music_file_info.artist_header },
3420 { "album_header", &tmp_music_file_info.album_header },
3421 { "year_header", &tmp_music_file_info.year_header },
3423 { "title", &tmp_music_file_info.title },
3424 { "artist", &tmp_music_file_info.artist },
3425 { "album", &tmp_music_file_info.album },
3426 { "year", &tmp_music_file_info.year },
3432 filename_music = (is_sound ? getCustomSoundFilename(basename) :
3433 getCustomMusicFilename(basename));
3435 if (filename_music == NULL)
3438 /* ---------- try to replace file extension ---------- */
3440 filename_prefix = getStringCopy(filename_music);
3441 if (strrchr(filename_prefix, '.') != NULL)
3442 *strrchr(filename_prefix, '.') = '\0';
3443 filename_info = getStringCat2(filename_prefix, ".txt");
3446 printf("trying to load file '%s'...\n", filename_info);
3449 if (fileExists(filename_info))
3450 setup_file_hash = loadSetupFileHash(filename_info);
3452 free(filename_prefix);
3453 free(filename_info);
3455 if (setup_file_hash == NULL)
3457 /* ---------- try to add file extension ---------- */
3459 filename_prefix = getStringCopy(filename_music);
3460 filename_info = getStringCat2(filename_prefix, ".txt");
3463 printf("trying to load file '%s'...\n", filename_info);
3466 if (fileExists(filename_info))
3467 setup_file_hash = loadSetupFileHash(filename_info);
3469 free(filename_prefix);
3470 free(filename_info);
3473 if (setup_file_hash == NULL)
3476 /* ---------- music file info found ---------- */
3478 memset(&tmp_music_file_info, 0, sizeof(struct MusicFileInfo));
3480 for (i = 0; token_to_value_ptr[i].token != NULL; i++)
3482 char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
3484 *token_to_value_ptr[i].value_ptr =
3485 getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
3488 tmp_music_file_info.basename = getStringCopy(basename);
3489 tmp_music_file_info.music = music;
3490 tmp_music_file_info.is_sound = is_sound;
3492 new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
3493 *new_music_file_info = tmp_music_file_info;
3495 return new_music_file_info;
3498 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
3500 return get_music_file_info_ext(basename, music, FALSE);
3503 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
3505 return get_music_file_info_ext(basename, sound, TRUE);
3508 static boolean music_info_listed_ext(struct MusicFileInfo *list,
3509 char *basename, boolean is_sound)
3511 for (; list != NULL; list = list->next)
3512 if (list->is_sound == is_sound && strcmp(list->basename, basename) == 0)
3518 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
3520 return music_info_listed_ext(list, basename, FALSE);
3523 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
3525 return music_info_listed_ext(list, basename, TRUE);
3528 void LoadMusicInfo()
3530 char *music_directory = getCustomMusicDirectory();
3531 int num_music = getMusicListSize();
3532 int num_music_noconf = 0;
3533 int num_sounds = getSoundListSize();
3535 struct dirent *dir_entry;
3536 struct FileInfo *music, *sound;
3537 struct MusicFileInfo *next, **new;
3540 while (music_file_info != NULL)
3542 next = music_file_info->next;
3544 checked_free(music_file_info->basename);
3546 checked_free(music_file_info->title_header);
3547 checked_free(music_file_info->artist_header);
3548 checked_free(music_file_info->album_header);
3549 checked_free(music_file_info->year_header);
3551 checked_free(music_file_info->title);
3552 checked_free(music_file_info->artist);
3553 checked_free(music_file_info->album);
3554 checked_free(music_file_info->year);
3556 free(music_file_info);
3558 music_file_info = next;
3561 new = &music_file_info;
3564 printf("::: num_music == %d\n", num_music);
3567 for (i = 0; i < num_music; i++)
3569 music = getMusicListEntry(i);
3572 printf("::: %d [%08x]\n", i, music->filename);
3575 if (music->filename == NULL)
3578 if (strcmp(music->filename, UNDEFINED_FILENAME) == 0)
3581 /* a configured file may be not recognized as music */
3582 if (!FileIsMusic(music->filename))
3586 printf("::: -> '%s' (configured)\n", music->filename);
3589 if (!music_info_listed(music_file_info, music->filename))
3591 *new = get_music_file_info(music->filename, i);
3593 new = &(*new)->next;
3597 if ((dir = opendir(music_directory)) == NULL)
3599 Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
3603 while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
3605 char *basename = dir_entry->d_name;
3606 boolean music_already_used = FALSE;
3609 /* skip all music files that are configured in music config file */
3610 for (i = 0; i < num_music; i++)
3612 music = getMusicListEntry(i);
3614 if (music->filename == NULL)
3617 if (strcmp(basename, music->filename) == 0)
3619 music_already_used = TRUE;
3624 if (music_already_used)
3627 if (!FileIsMusic(basename))
3631 printf("::: -> '%s' (found in directory)\n", basename);
3634 if (!music_info_listed(music_file_info, basename))
3636 *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
3638 new = &(*new)->next;
3646 for (i = 0; i < num_sounds; i++)
3648 sound = getSoundListEntry(i);
3650 if (sound->filename == NULL)
3653 if (strcmp(sound->filename, UNDEFINED_FILENAME) == 0)
3656 /* a configured file may be not recognized as sound */
3657 if (!FileIsSound(sound->filename))
3661 printf("::: -> '%s' (configured)\n", sound->filename);
3664 if (!sound_info_listed(music_file_info, sound->filename))
3666 *new = get_sound_file_info(sound->filename, i);
3668 new = &(*new)->next;
3674 for (next = music_file_info; next != NULL; next = next->next)
3675 printf("::: title == '%s'\n", next->title);
3679 void add_helpanim_entry(int element, int action, int direction, int delay,
3680 int *num_list_entries)
3682 struct HelpAnimInfo *new_list_entry;
3683 (*num_list_entries)++;
3686 checked_realloc(helpanim_info,
3687 *num_list_entries * sizeof(struct HelpAnimInfo));
3688 new_list_entry = &helpanim_info[*num_list_entries - 1];
3690 new_list_entry->element = element;
3691 new_list_entry->action = action;
3692 new_list_entry->direction = direction;
3693 new_list_entry->delay = delay;
3696 void print_unknown_token(char *filename, char *token, int token_nr)
3700 Error(ERR_RETURN_LINE, "-");
3701 Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
3702 Error(ERR_RETURN, "- config file: '%s'", filename);
3705 Error(ERR_RETURN, "- token: '%s'", token);
3708 void print_unknown_token_end(int token_nr)
3711 Error(ERR_RETURN_LINE, "-");
3714 void LoadHelpAnimInfo()
3716 char *filename = getHelpAnimFilename();
3717 SetupFileList *setup_file_list = NULL, *list;
3718 SetupFileHash *element_hash, *action_hash, *direction_hash;
3719 int num_list_entries = 0;
3720 int num_unknown_tokens = 0;
3723 if (fileExists(filename))
3724 setup_file_list = loadSetupFileList(filename);
3726 if (setup_file_list == NULL)
3728 /* use reliable default values from static configuration */
3729 SetupFileList *insert_ptr;
3731 insert_ptr = setup_file_list =
3732 newSetupFileList(helpanim_config[0].token,
3733 helpanim_config[0].value);
3735 for (i = 1; helpanim_config[i].token; i++)
3736 insert_ptr = addListEntry(insert_ptr,
3737 helpanim_config[i].token,
3738 helpanim_config[i].value);
3741 element_hash = newSetupFileHash();
3742 action_hash = newSetupFileHash();
3743 direction_hash = newSetupFileHash();
3745 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3746 setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
3748 for (i = 0; i < NUM_ACTIONS; i++)
3749 setHashEntry(action_hash, element_action_info[i].suffix,
3750 i_to_a(element_action_info[i].value));
3752 /* do not store direction index (bit) here, but direction value! */
3753 for (i = 0; i < NUM_DIRECTIONS; i++)
3754 setHashEntry(direction_hash, element_direction_info[i].suffix,
3755 i_to_a(1 << element_direction_info[i].value));
3757 for (list = setup_file_list; list != NULL; list = list->next)
3759 char *element_token, *action_token, *direction_token;
3760 char *element_value, *action_value, *direction_value;
3761 int delay = atoi(list->value);
3763 if (strcmp(list->token, "end") == 0)
3765 add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
3770 /* first try to break element into element/action/direction parts;
3771 if this does not work, also accept combined "element[.act][.dir]"
3772 elements (like "dynamite.active"), which are unique elements */
3774 if (strchr(list->token, '.') == NULL) /* token contains no '.' */
3776 element_value = getHashEntry(element_hash, list->token);
3777 if (element_value != NULL) /* element found */
3778 add_helpanim_entry(atoi(element_value), -1, -1, delay,
3782 /* no further suffixes found -- this is not an element */
3783 print_unknown_token(filename, list->token, num_unknown_tokens++);
3789 /* token has format "<prefix>.<something>" */
3791 action_token = strchr(list->token, '.'); /* suffix may be action ... */
3792 direction_token = action_token; /* ... or direction */
3794 element_token = getStringCopy(list->token);
3795 *strchr(element_token, '.') = '\0';
3797 element_value = getHashEntry(element_hash, element_token);
3799 if (element_value == NULL) /* this is no element */
3801 element_value = getHashEntry(element_hash, list->token);
3802 if (element_value != NULL) /* combined element found */
3803 add_helpanim_entry(atoi(element_value), -1, -1, delay,
3806 print_unknown_token(filename, list->token, num_unknown_tokens++);
3808 free(element_token);
3813 action_value = getHashEntry(action_hash, action_token);
3815 if (action_value != NULL) /* action found */
3817 add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
3820 free(element_token);
3825 direction_value = getHashEntry(direction_hash, direction_token);
3827 if (direction_value != NULL) /* direction found */
3829 add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
3832 free(element_token);
3837 if (strchr(action_token + 1, '.') == NULL)
3839 /* no further suffixes found -- this is not an action nor direction */
3841 element_value = getHashEntry(element_hash, list->token);
3842 if (element_value != NULL) /* combined element found */
3843 add_helpanim_entry(atoi(element_value), -1, -1, delay,
3846 print_unknown_token(filename, list->token, num_unknown_tokens++);
3848 free(element_token);
3853 /* token has format "<prefix>.<suffix>.<something>" */
3855 direction_token = strchr(action_token + 1, '.');
3857 action_token = getStringCopy(action_token);
3858 *strchr(action_token + 1, '.') = '\0';
3860 action_value = getHashEntry(action_hash, action_token);
3862 if (action_value == NULL) /* this is no action */
3864 element_value = getHashEntry(element_hash, list->token);
3865 if (element_value != NULL) /* combined element found */
3866 add_helpanim_entry(atoi(element_value), -1, -1, delay,
3869 print_unknown_token(filename, list->token, num_unknown_tokens++);
3871 free(element_token);
3877 direction_value = getHashEntry(direction_hash, direction_token);
3879 if (direction_value != NULL) /* direction found */
3881 add_helpanim_entry(atoi(element_value), atoi(action_value),
3882 atoi(direction_value), delay, &num_list_entries);
3884 free(element_token);
3890 /* this is no direction */
3892 element_value = getHashEntry(element_hash, list->token);
3893 if (element_value != NULL) /* combined element found */
3894 add_helpanim_entry(atoi(element_value), -1, -1, delay,
3897 print_unknown_token(filename, list->token, num_unknown_tokens++);
3899 free(element_token);
3903 print_unknown_token_end(num_unknown_tokens);
3905 add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
3906 add_helpanim_entry(HELPANIM_LIST_END, -1, -1, -1, &num_list_entries);
3908 freeSetupFileList(setup_file_list);
3909 freeSetupFileHash(element_hash);
3910 freeSetupFileHash(action_hash);
3911 freeSetupFileHash(direction_hash);
3915 for (i = 0; i < num_list_entries; i++)
3916 printf("::: %d, %d, %d => %d\n",
3917 helpanim_info[i].element,
3918 helpanim_info[i].action,
3919 helpanim_info[i].direction,
3920 helpanim_info[i].delay);
3924 void LoadHelpTextInfo()
3926 char *filename = getHelpTextFilename();
3929 if (helptext_info != NULL)
3931 freeSetupFileHash(helptext_info);
3932 helptext_info = NULL;
3935 if (fileExists(filename))
3936 helptext_info = loadSetupFileHash(filename);
3938 if (helptext_info == NULL)
3940 /* use reliable default values from static configuration */
3941 helptext_info = newSetupFileHash();
3943 for (i = 0; helptext_config[i].token; i++)
3944 setHashEntry(helptext_info,
3945 helptext_config[i].token,
3946 helptext_config[i].value);
3951 BEGIN_HASH_ITERATION(helptext_info, itr)
3953 printf("::: '%s' => '%s'\n",
3954 HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
3956 END_HASH_ITERATION(hash, itr)