- -1, -1,
- NULL, -1
- }
-};
-
-static struct
-{
- int filetype;
- char *id;
-}
-filetype_id_list[] =
-{
- { LEVEL_FILE_TYPE_RND, "RND" },
- { LEVEL_FILE_TYPE_BD, "BD" },
- { LEVEL_FILE_TYPE_EM, "EM" },
- { LEVEL_FILE_TYPE_SP, "SP" },
- { LEVEL_FILE_TYPE_DX, "DX" },
- { LEVEL_FILE_TYPE_SB, "SB" },
- { LEVEL_FILE_TYPE_DC, "DC" },
- { LEVEL_FILE_TYPE_MM, "MM" },
- { LEVEL_FILE_TYPE_MM, "DF" },
- { -1, NULL },
-};
-
-
-// ============================================================================
-// level file functions
-// ============================================================================
-
-static boolean check_special_flags(char *flag)
-{
- if (strEqual(options.special_flags, flag) ||
- strEqual(leveldir_current->special_flags, flag))
- return TRUE;
-
- return FALSE;
-}
-
-static struct DateInfo getCurrentDate(void)
-{
- time_t epoch_seconds = time(NULL);
- struct tm *now = localtime(&epoch_seconds);
- struct DateInfo date;
-
- date.year = now->tm_year + 1900;
- date.month = now->tm_mon + 1;
- date.day = now->tm_mday;
-
- date.src = DATE_SRC_CLOCK;
-
- return date;
-}
-
-static void resetEventFlags(struct ElementChangeInfo *change)
-{
- int i;
-
- for (i = 0; i < NUM_CHANGE_EVENTS; i++)
- change->has_event[i] = FALSE;
-}
-
-static void resetEventBits(void)
-{
- int i;
-
- for (i = 0; i < NUM_CE_BITFIELDS; i++)
- xx_event_bits[i] = 0;
-}
-
-static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
-{
- int i;
-
- /* important: only change event flag if corresponding event bit is set
- (this is because all xx_event_bits[] values are loaded separately,
- and all xx_event_bits[] values are set back to zero before loading
- another value xx_event_bits[x] (each value representing 32 flags)) */
-
- for (i = 0; i < NUM_CHANGE_EVENTS; i++)
- if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i))
- change->has_event[i] = TRUE;
-}
-
-static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
-{
- int i;
-
- /* in contrast to the above function setEventFlagsFromEventBits(), it
- would also be possible to set all bits in xx_event_bits[] to 0 or 1
- depending on the corresponding change->has_event[i] values here, as
- all xx_event_bits[] values are reset in resetEventBits() before */
-
- for (i = 0; i < NUM_CHANGE_EVENTS; i++)
- if (change->has_event[i])
- xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i);
-}
-
-static char *getDefaultElementDescription(struct ElementInfo *ei)
-{
- static char description[MAX_ELEMENT_NAME_LEN + 1];
- char *default_description = (ei->custom_description != NULL ?
- ei->custom_description :
- ei->editor_description);
- int i;
-
- // always start with reliable default values
- for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
- description[i] = '\0';
-
- // truncate element description to MAX_ELEMENT_NAME_LEN bytes
- strncpy(description, default_description, MAX_ELEMENT_NAME_LEN);
-
- return &description[0];
-}
-
-static void setElementDescriptionToDefault(struct ElementInfo *ei)
-{
- char *default_description = getDefaultElementDescription(ei);
- int i;
-
- for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
- ei->description[i] = default_description[i];
-}
-
-static void setConfigToDefaultsFromConfigList(struct LevelFileConfigInfo *conf)
-{
- int i;
-
- for (i = 0; conf[i].data_type != -1; i++)
- {
- int default_value = conf[i].default_value;
- int data_type = conf[i].data_type;
- int conf_type = conf[i].conf_type;
- int byte_mask = conf_type & CONF_MASK_BYTES;
-
- if (byte_mask == CONF_MASK_MULTI_BYTES)
- {
- int default_num_entities = conf[i].default_num_entities;
- int max_num_entities = conf[i].max_num_entities;
-
- *(int *)(conf[i].num_entities) = default_num_entities;
-
- if (data_type == TYPE_STRING)
- {
- char *default_string = conf[i].default_string;
- char *string = (char *)(conf[i].value);
-
- strncpy(string, default_string, max_num_entities);
- }
- else if (data_type == TYPE_ELEMENT_LIST)
- {
- int *element_array = (int *)(conf[i].value);
- int j;
-
- for (j = 0; j < max_num_entities; j++)
- element_array[j] = default_value;
- }
- else if (data_type == TYPE_CONTENT_LIST)
- {
- struct Content *content = (struct Content *)(conf[i].value);
- int c, x, y;
-
- for (c = 0; c < max_num_entities; c++)
- for (y = 0; y < 3; y++)
- for (x = 0; x < 3; x++)
- content[c].e[x][y] = default_value;
- }
- }
- else // constant size configuration data (1, 2 or 4 bytes)
- {
- if (data_type == TYPE_BOOLEAN)
- *(boolean *)(conf[i].value) = default_value;
- else
- *(int *) (conf[i].value) = default_value;
- }
- }
-}
-
-static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf)
-{
- int i;
-
- for (i = 0; conf[i].data_type != -1; i++)
- {
- int data_type = conf[i].data_type;
- int conf_type = conf[i].conf_type;
- int byte_mask = conf_type & CONF_MASK_BYTES;
-
- if (byte_mask == CONF_MASK_MULTI_BYTES)
- {
- int max_num_entities = conf[i].max_num_entities;
-
- if (data_type == TYPE_STRING)
- {
- char *string = (char *)(conf[i].value);
- char *string_copy = (char *)(conf[i].value_copy);
-
- strncpy(string_copy, string, max_num_entities);
- }
- else if (data_type == TYPE_ELEMENT_LIST)
- {
- int *element_array = (int *)(conf[i].value);
- int *element_array_copy = (int *)(conf[i].value_copy);
- int j;
-
- for (j = 0; j < max_num_entities; j++)
- element_array_copy[j] = element_array[j];
- }
- else if (data_type == TYPE_CONTENT_LIST)
- {
- struct Content *content = (struct Content *)(conf[i].value);
- struct Content *content_copy = (struct Content *)(conf[i].value_copy);
- int c, x, y;
-
- for (c = 0; c < max_num_entities; c++)
- for (y = 0; y < 3; y++)
- for (x = 0; x < 3; x++)
- content_copy[c].e[x][y] = content[c].e[x][y];
- }
- }
- else // constant size configuration data (1, 2 or 4 bytes)
- {
- if (data_type == TYPE_BOOLEAN)
- *(boolean *)(conf[i].value_copy) = *(boolean *)(conf[i].value);
- else
- *(int *) (conf[i].value_copy) = *(int *) (conf[i].value);
- }
- }
-}
-
-void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
-{
- int i;
-
- xx_ei = *ei_from; // copy element data into temporary buffer
- yy_ei = *ei_to; // copy element data into temporary buffer
-
- copyConfigFromConfigList(chunk_config_CUSX_base);
-
- *ei_from = xx_ei;
- *ei_to = yy_ei;
-
- // ---------- reinitialize and copy change pages ----------
-
- ei_to->num_change_pages = ei_from->num_change_pages;
- ei_to->current_change_page = ei_from->current_change_page;
-
- setElementChangePages(ei_to, ei_to->num_change_pages);
-
- for (i = 0; i < ei_to->num_change_pages; i++)
- ei_to->change_page[i] = ei_from->change_page[i];
-
- // ---------- copy group element info ----------
- if (ei_from->group != NULL && ei_to->group != NULL) // group or internal
- *ei_to->group = *ei_from->group;
-
- // mark this custom element as modified
- ei_to->modified_settings = TRUE;
-}
-
-void setElementChangePages(struct ElementInfo *ei, int change_pages)
-{
- int change_page_size = sizeof(struct ElementChangeInfo);
-
- ei->num_change_pages = MAX(1, change_pages);
-
- ei->change_page =
- checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
-
- if (ei->current_change_page >= ei->num_change_pages)
- ei->current_change_page = ei->num_change_pages - 1;
-
- ei->change = &ei->change_page[ei->current_change_page];
-}
-
-void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
-{
- xx_change = *change; // copy change data into temporary buffer
-
- setConfigToDefaultsFromConfigList(chunk_config_CUSX_change);
-
- *change = xx_change;
-
- resetEventFlags(change);
-
- change->direct_action = 0;
- change->other_action = 0;
-
- change->pre_change_function = NULL;
- change->change_function = NULL;
- change->post_change_function = NULL;
-}
-
-static void setLevelInfoToDefaults_Level(struct LevelInfo *level)
-{
- int i, x, y;
-
- li = *level; // copy level data into temporary buffer
- setConfigToDefaultsFromConfigList(chunk_config_INFO);
- *level = li; // copy temporary buffer back to level data
-
- setLevelInfoToDefaults_EM();
- setLevelInfoToDefaults_SP();
- setLevelInfoToDefaults_MM();
-
- level->native_em_level = &native_em_level;
- level->native_sp_level = &native_sp_level;
- level->native_mm_level = &native_mm_level;
-
- level->file_version = FILE_VERSION_ACTUAL;
- level->game_version = GAME_VERSION_ACTUAL;
-
- level->creation_date = getCurrentDate();
-
- level->encoding_16bit_field = TRUE;
- level->encoding_16bit_yamyam = TRUE;
- level->encoding_16bit_amoeba = TRUE;
-
- // clear level name and level author string buffers
- for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
- level->name[i] = '\0';
- for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
- level->author[i] = '\0';
-
- // set level name and level author to default values
- strcpy(level->name, NAMELESS_LEVEL_NAME);
- strcpy(level->author, ANONYMOUS_NAME);
-
- // set level playfield to playable default level with player and exit
- for (x = 0; x < MAX_LEV_FIELDX; x++)
- for (y = 0; y < MAX_LEV_FIELDY; y++)
- level->field[x][y] = EL_SAND;
-
- level->field[0][0] = EL_PLAYER_1;
- level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
-
- BorderElement = EL_STEELWALL;
-
- // detect custom elements when loading them
- level->file_has_custom_elements = FALSE;
-
- // set all bug compatibility flags to "false" => do not emulate this bug
- level->use_action_after_change_bug = FALSE;
-
- if (leveldir_current)
- {
- // try to determine better author name than 'anonymous'
- if (!strEqual(leveldir_current->author, ANONYMOUS_NAME))
- {
- strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
- level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
- }
- else
- {
- switch (LEVELCLASS(leveldir_current))
- {
- case LEVELCLASS_TUTORIAL:
- strcpy(level->author, PROGRAM_AUTHOR_STRING);
- break;
-
- case LEVELCLASS_CONTRIB:
- strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
- level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
- break;
-
- case LEVELCLASS_PRIVATE:
- strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
- level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
- break;
-
- default:
- // keep default value
- break;
- }
- }
- }
-}
-
-static void setLevelInfoToDefaults_Elements(struct LevelInfo *level)
-{
- static boolean clipboard_elements_initialized = FALSE;
- int i;
-
- InitElementPropertiesStatic();
-
- li = *level; // copy level data into temporary buffer
- setConfigToDefaultsFromConfigList(chunk_config_ELEM);
- *level = li; // copy temporary buffer back to level data
-
- for (i = 0; i < MAX_NUM_ELEMENTS; i++)
- {
- int element = i;
- struct ElementInfo *ei = &element_info[element];
-
- // never initialize clipboard elements after the very first time
- // (to be able to use clipboard elements between several levels)
- if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
- continue;
-
- if (IS_ENVELOPE(element))
- {
- int envelope_nr = element - EL_ENVELOPE_1;
-
- setConfigToDefaultsFromConfigList(chunk_config_NOTE);
-
- level->envelope[envelope_nr] = xx_envelope;
- }
-
- if (IS_CUSTOM_ELEMENT(element) ||
- IS_GROUP_ELEMENT(element) ||
- IS_INTERNAL_ELEMENT(element))
- {
- xx_ei = *ei; // copy element data into temporary buffer
-
- setConfigToDefaultsFromConfigList(chunk_config_CUSX_base);
-
- *ei = xx_ei;
- }
-
- setElementChangePages(ei, 1);
- setElementChangeInfoToDefaults(ei->change);
-
- if (IS_CUSTOM_ELEMENT(element) ||
- IS_GROUP_ELEMENT(element) ||
- IS_INTERNAL_ELEMENT(element))
- {
- setElementDescriptionToDefault(ei);
-
- ei->modified_settings = FALSE;
- }
-
- if (IS_CUSTOM_ELEMENT(element) ||
- IS_INTERNAL_ELEMENT(element))
- {
- // internal values used in level editor
-
- ei->access_type = 0;
- ei->access_layer = 0;
- ei->access_protected = 0;
- ei->walk_to_action = 0;
- ei->smash_targets = 0;
- ei->deadliness = 0;
-
- ei->can_explode_by_fire = FALSE;
- ei->can_explode_smashed = FALSE;
- ei->can_explode_impact = FALSE;
-
- ei->current_change_page = 0;
- }
-
- if (IS_GROUP_ELEMENT(element) ||
- IS_INTERNAL_ELEMENT(element))
- {
- struct ElementGroupInfo *group;