X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ffiles.c;h=0d4f895c34c050bd381c1df74a63ad641975b1f2;hb=d9b86b7b2ebe0b2be3926656c3bbdcd060ee5811;hp=6db3036e8685a742545a7cc8207e173891701bfc;hpb=63f41483ea7866802a7f6382c1d1b7135a1cd86a;p=rocksndiamonds.git diff --git a/src/files.c b/src/files.c index 6db3036e..0d4f895c 100644 --- a/src/files.c +++ b/src/files.c @@ -86,8 +86,8 @@ #define CONF_VALUE_ELEMENT_7 (CONF_MASK_2_BYTE | 7) #define CONF_VALUE_ELEMENT_8 (CONF_MASK_2_BYTE | 8) -#define CONF_VALUE_CONTENT_1 (CONF_MASK_MULTI_BYTES | 1) -#define CONF_VALUE_CONTENT_8 (CONF_MASK_MULTI_BYTES | 2) +#define CONF_VALUE_ELEMENTS (CONF_MASK_MULTI_BYTES | 1) +#define CONF_VALUE_CONTENTS (CONF_MASK_MULTI_BYTES | 2) #define CONF_VALUE_INTEGER(x) ((x) >= CONF_VALUE_INTEGER_1 && \ (x) <= CONF_VALUE_INTEGER_8) @@ -101,24 +101,47 @@ #define CONF_CONTENT_NUM_ELEMENTS (3 * 3) #define CONF_CONTENT_NUM_BYTES (CONF_CONTENT_NUM_ELEMENTS * 2) +#define CONF_ELEMENT_NUM_BYTES (2) + +#define CONF_ENTITY_NUM_BYTES(t) ((t) == CONF_VALUE_ELEMENTS ? \ + CONF_ELEMENT_NUM_BYTES : \ + (t) == CONF_VALUE_CONTENTS ? \ + CONF_CONTENT_NUM_BYTES : 1) + +#define CONF_ELEMENT_BYTE_POS(i) ((i) * CONF_ELEMENT_NUM_BYTES) +#define CONF_ELEMENTS_ELEMENT(b,i) ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) | \ + (b[CONF_ELEMENT_BYTE_POS(i) + 1])) #define CONF_CONTENT_ELEMENT_POS(c,x,y) ((c) * CONF_CONTENT_NUM_ELEMENTS + \ (y) * 3 + (x)) -#define CONF_CONTENT_BYTE_POS(c,x,y) (CONF_CONTENT_ELEMENT_POS(c,x,y) * 2) -#define CONF_CONTENT_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)] << 8)|\ - (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1])) +#define CONF_CONTENT_BYTE_POS(c,x,y) (CONF_CONTENT_ELEMENT_POS(c,x,y) * \ + CONF_ELEMENT_NUM_BYTES) +#define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\ + (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1])) + +#if 0 +static void LoadLevel_InitPlayfield(struct LevelInfo *, char *); +#endif static struct LevelInfo li; static struct { - int element; - int type; - void *value; - int default_value; + int element; /* element for which data is to be stored */ + int type; /* type of data to be stored */ + + /* (mandatory) */ + void *value; /* variable that holds the data to be stored */ + int default_value; /* initial default value for this variable */ + + /* (optional) */ + void *num_entities; /* number of entities for multi-byte data */ + int default_num_entities; /* default number of entities for this data */ + int max_num_entities; /* maximal number of entities for this data */ } element_conf[] = { /* ---------- 1-byte values ---------------------------------------------- */ + { EL_EMC_ANDROID, CONF_VALUE_INTEGER_1, &li.android_move_time, 10 @@ -268,12 +291,12 @@ static struct &li.use_explosion_element[3], FALSE }, { - EL_EMC_MAGIC_BALL, CONF_VALUE_INTEGER_1, - &li.ball_time, 10 + EL_PLAYER_1, CONF_VALUE_INTEGER_1, + &li.initial_player_stepsize, STEPSIZE_NORMAL }, { - EL_EMC_MAGIC_BALL, CONF_VALUE_INTEGER_2, - &li.num_ball_contents, 8 + EL_EMC_MAGIC_BALL, CONF_VALUE_INTEGER_1, + &li.ball_time, 10 }, { EL_EMC_MAGIC_BALL, CONF_VALUE_BOOLEAN_1, @@ -285,6 +308,7 @@ static struct }, /* ---------- 2-byte values ---------------------------------------------- */ + { EL_PLAYER_1, CONF_VALUE_ELEMENT_1, &li.start_element[0], EL_PLAYER_1 @@ -335,14 +359,21 @@ static struct }, /* ---------- multi-byte values ------------------------------------------ */ + + { + EL_EMC_MAGIC_BALL, CONF_VALUE_CONTENTS, + &li.ball_content, EL_EMPTY, + &li.num_ball_contents, 4, MAX_ELEMENT_CONTENTS + }, { - EL_EMC_MAGIC_BALL, CONF_VALUE_CONTENT_8, - &li.ball_content, EL_EMPTY + EL_EMC_ANDROID, CONF_VALUE_ELEMENTS, + &li.android_clone_element[0], EL_EMPTY, + &li.num_android_clone_elements, 1, MAX_ANDROID_ELEMENTS }, { -1, -1, - NULL, -1 + NULL, -1, }, }; @@ -380,23 +411,39 @@ static void setLevelInfoToDefaultsFromConfigList(struct LevelInfo *level) int type = element_conf[i].type; int bytes = type & CONF_MASK_BYTES; - if (bytes != CONF_MASK_MULTI_BYTES) + if (bytes == CONF_MASK_MULTI_BYTES) + { + int default_num_entities = element_conf[i].default_num_entities; + int max_num_entities = element_conf[i].max_num_entities; + + *(int *)(element_conf[i].num_entities) = default_num_entities; + + if (type == CONF_VALUE_ELEMENTS) + { + int *element_array = (int *)(element_conf[i].value); + int j; + + for (j = 0; j < max_num_entities; j++) + element_array[j] = default_value; + } + else if (type == CONF_VALUE_CONTENTS) + { + struct Content *content = (struct Content *)(element_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 (CONF_VALUE_BOOLEAN(type)) *(boolean *)(element_conf[i].value) = default_value; else *(int *) (element_conf[i].value) = default_value; } - else if (type == CONF_VALUE_CONTENT_8) - { - struct Content *content = (struct Content *)(element_conf[i].value); - int c, x, y; - - for (c = 0; c < MAX_ELEMENT_CONTENTS; c++) - for (y = 0; y < 3; y++) - for (x = 0; x < 3; x++) - content[c].e[x][y] = default_value; - } } *level = li; /* copy temporary buffer back to level information */ @@ -516,7 +563,9 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) level->biomaze[2] = 3; level->biomaze[3] = 3; +#if 0 level->double_speed = FALSE; +#endif level->initial_gravity = FALSE; level->em_slippery_gems = FALSE; level->instant_relocation = FALSE; @@ -554,8 +603,10 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) for (y = 0; y < 3; y++) level->ball_content[i].e[x][y] = EL_EMPTY; #endif +#if 0 for (i = 0; i < 16; i++) level->android_array[i] = FALSE; +#endif level->use_custom_template = FALSE; @@ -671,8 +722,13 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) /* !!! now done in InitElementPropertiesStatic() (see above) !!! */ /* !!! (else properties set there will be overwritten here) !!! */ /* start with no properties at all */ +#if 1 + for (j = 0; j < NUM_EP_BITFIELDS; j++) + ei->properties[j] = EP_BITMASK_DEFAULT; +#else for (j = 0; j < NUM_EP_BITFIELDS; j++) Properties[element][j] = EP_BITMASK_DEFAULT; +#endif #endif /* now set default properties */ @@ -753,9 +809,15 @@ static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info) static void ActivateLevelTemplate() { +#if 1 + /* Currently there is no special action needed to activate the template + data, because 'element_info' property settings overwrite the original + level data, while all other variables do not change. */ +#else /* Currently there is no special action needed to activate the template data, because 'element_info' and 'Properties' overwrite the original level data, while all other variables do not change. */ +#endif } static char *getLevelFilenameFromBasename(char *basename) @@ -1132,7 +1194,10 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level) level->time_magic_wall = getFile8Bit(file); level->time_wheel = getFile8Bit(file); level->amoeba_content = getMappedElement(getFile8Bit(file)); - level->double_speed = (getFile8Bit(file) == 1 ? TRUE : FALSE); + + level->initial_player_stepsize = (getFile8Bit(file) == 1 ? STEPSIZE_FAST : + STEPSIZE_NORMAL); + level->initial_gravity = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->encoding_16bit_field = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->em_slippery_gems = (getFile8Bit(file) == 1 ? TRUE : FALSE); @@ -1331,10 +1396,17 @@ static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level) int element = getFile16BitBE(file); int properties = getFile32BitBE(file); +#if 1 + if (IS_CUSTOM_ELEMENT(element)) + element_info[element].properties[EP_BITFIELD_BASE] = properties; + else + Error(ERR_WARN, "invalid custom element number %d", element); +#else if (IS_CUSTOM_ELEMENT(element)) Properties[element][EP_BITFIELD_BASE] = properties; else Error(ERR_WARN, "invalid custom element number %d", element); +#endif } return chunk_size; @@ -1395,7 +1467,11 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level) ei->description[j] = getFile8Bit(file); ei->description[MAX_ELEMENT_NAME_LEN] = 0; +#if 1 + ei->properties[EP_BITFIELD_BASE] = getFile32BitBE(file); +#else Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file); +#endif /* some free bytes for future properties and padding */ ReadUnusedBytesFromFile(file, 7); @@ -1482,7 +1558,11 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) ei->description[i] = getFile8Bit(file); ei->description[MAX_ELEMENT_NAME_LEN] = 0; +#if 1 + ei->properties[EP_BITFIELD_BASE] = getFile32BitBE(file); +#else Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file); +#endif ReadUnusedBytesFromFile(file, 4); /* reserved for more base properties */ ei->num_change_pages = getFile8Bit(file); @@ -1676,19 +1756,41 @@ static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level) if (element_conf[i].element == element && element_conf[i].type == type) { + int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(type); + int max_num_entities = element_conf[i].max_num_entities; + + if (num_entities > max_num_entities) + { + Error(ERR_WARN, + "truncating number of entities for element %d from %d to %d", + element, num_entities, max_num_entities); + + num_entities = max_num_entities; + } + + *(int *)(element_conf[i].num_entities) = num_entities; + element_found = TRUE; - if (type == CONF_VALUE_CONTENT_8) + if (type == CONF_VALUE_ELEMENTS) + { + int *element_array = (int *)(element_conf[i].value); + int j; + + for (j = 0; j < num_entities; j++) + element_array[j] = + getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j)); + } + else if (type == CONF_VALUE_CONTENTS) { struct Content *content= (struct Content *)(element_conf[i].value); - int num_contents = num_bytes / CONF_CONTENT_NUM_BYTES; int c, x, y; - for (c = 0; c < num_contents; c++) + for (c = 0; c < num_entities; c++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content[c].e[x][y] = - getMappedElement(CONF_CONTENT_ELEMENT(buffer, c, x, y)); + getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y)); } else element_found = FALSE; @@ -1701,7 +1803,7 @@ static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level) real_chunk_size += 2 + num_bytes; } - else + else /* constant size configuration data (1, 2 or 4 bytes) */ { int value = (bytes == CONF_MASK_1_BYTE ? getFile8Bit (file) : bytes == CONF_MASK_2_BYTE ? getFile16BitBE(file) : @@ -2317,10 +2419,17 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) }; struct LevelInfo_EM *level_em = level->native_em_level; struct LEVEL *lev = level_em->lev; - struct PLAYER *ply1 = level_em->ply1; - struct PLAYER *ply2 = level_em->ply2; + struct PLAYER **ply = level_em->ply; int i, j, x, y; +#if 0 + printf("::: A\n"); + for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) + for (j = 0; j < 8; j++) + printf("::: ball %d, %d: %d\n", i, j, + level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]); +#endif + lev->width = MIN(level->fieldx, EM_MAX_CAVE_WIDTH); lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT); @@ -2373,14 +2482,64 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) map_element_RND_to_EM(level-> ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]); +#if 0 + for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) + for (j = 0; j < 8; j++) + printf("::: ball %d, %d: %d\n", i, j, + level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]); +#endif + + map_android_clone_elements_RND_to_EM(level); + +#if 0 for (i = 0; i < 16; i++) lev->android_array[i] = FALSE; /* !!! YET TO COME !!! */ +#endif /* first fill the complete playfield with the default border element */ for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++) for (x = 0; x < EM_MAX_CAVE_WIDTH; x++) level_em->cave[x][y] = ZBORDER; +#if 1 + +#if 0 +#if 1 + LoadLevel_InitPlayfield(); +#else + lev_fieldx = lev->width; /* !!! also in LoadLevel_InitPlayfield() !!! */ + lev_fieldy = lev->height; /* !!! also in LoadLevel_InitPlayfield() !!! */ + SetBorderElement(); /* !!! also in LoadLevel_InitPlayfield() !!! */ +#endif +#endif + +#if 0 + printf("::: BorderElement == %d\n", BorderElement); +#endif + + if (BorderElement == EL_STEELWALL) + { + for (y = 0; y < lev->height + 2; y++) + for (x = 0; x < lev->width + 2; x++) + level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL); + } + + /* then copy the real level contents from level file into the playfield */ + for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++) + { + int new_element = map_element_RND_to_EM(level->field[x][y]); + int offset = (BorderElement == EL_STEELWALL ? 1 : 0); + int xx = x + 1 + offset; + int yy = y + 1 + offset; + + if (level->field[x][y] == EL_AMOEBA_DEAD) + new_element = map_element_RND_to_EM(EL_AMOEBA_WET); + + level_em->cave[xx][yy] = new_element; + } + +#else + /* then copy the real level contents from level file into the playfield */ for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++) { @@ -2392,15 +2551,46 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) level_em->cave[x + 1][y + 1] = new_element; } +#endif + +#if 1 + + for (i = 0; i < MAX_PLAYERS; i++) + { + ply[i]->x_initial = 0; + ply[i]->y_initial = 0; + } + +#else + ply1->x_initial = 0; ply1->y_initial = 0; ply2->x_initial = 0; ply2->y_initial = 0; +#endif + /* initialize player positions and delete players from the playfield */ for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++) { + +#if 1 + if (ELEM_IS_PLAYER(level->field[x][y])) + { + int player_nr = GET_PLAYER_NR(level->field[x][y]); + int offset = (BorderElement == EL_STEELWALL ? 1 : 0); + int xx = x + 1 + offset; + int yy = y + 1 + offset; + + ply[player_nr]->x_initial = xx; + ply[player_nr]->y_initial = yy; + + level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY); + } + +#else + #if 1 /* !!! CURRENTLY ONLY SUPPORT FOR ONE PLAYER !!! */ if (ELEM_IS_PLAYER(level->field[x][y])) @@ -2424,6 +2614,17 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY); } #endif + +#endif + + } + + if (BorderElement == EL_STEELWALL) + { +#if 1 + lev->width += 2; + lev->height += 2; +#endif } } @@ -2442,8 +2643,7 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level) }; struct LevelInfo_EM *level_em = level->native_em_level; struct LEVEL *lev = level_em->lev; - struct PLAYER *ply1 = level_em->ply1; - struct PLAYER *ply2 = level_em->ply2; + struct PLAYER **ply = level_em->ply; int i, j, x, y; level->fieldx = MIN(lev->width, MAX_LEV_FIELDX); @@ -2494,13 +2694,33 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level) level->wind_direction_initial = map_direction_EM_to_RND(lev->wind_direction_initial); +#if 0 + printf("::: foo\n"); + for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) + for (j = 0; j < 8; j++) + printf("::: ball %d, %d: %d\n", i, j, + level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]); +#endif + for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (j = 0; j < 8; j++) level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] = map_element_EM_to_RND(lev->ball_array[i][j]); +#if 0 + printf("::: bar\n"); + for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) + for (j = 0; j < 8; j++) + printf("::: ball %d, %d: %d\n", i, j, + level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]); +#endif + + map_android_clone_elements_EM_to_RND(level); + +#if 0 for (i = 0; i < 16; i++) level->android_array[i] = FALSE; /* !!! YET TO COME !!! */ +#endif /* convert the playfield (some elements need special treatment) */ for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) @@ -2513,13 +2733,50 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level) level->field[x][y] = new_element; } +#if 0 + printf("::: bar 0\n"); + for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) + for (j = 0; j < 8; j++) + printf("::: ball %d, %d: %d\n", i, j, + level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]); +#endif + +#if 1 + + for (i = 0; i < MAX_PLAYERS; i++) + { + /* in case of all players set to the same field, use the first player */ + int nr = MAX_PLAYERS - i - 1; + int jx = ply[nr]->x_initial - 1; + int jy = ply[nr]->y_initial - 1; + +#if 0 + printf("::: player %d: %d, %d\n", nr, jx, jy); +#endif + + if (jx != -1 && jy != -1) + level->field[jx][jy] = EL_PLAYER_1 + nr; + } + +#else + /* in case of both players set to the same field, use the first player */ level->field[ply2->x_initial - 1][ply2->y_initial - 1] = EL_PLAYER_2; level->field[ply1->x_initial - 1][ply1->y_initial - 1] = EL_PLAYER_1; +#endif + #if 0 printf("::: native Emerald Mine file version: %d\n", level_em->file_version); #endif + +#if 0 + printf("::: bar 2\n"); + for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) + for (j = 0; j < 8; j++) + printf("::: ball %d, %d: %d\n", i, j, + level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]); +#endif } static void LoadLevelFromFileInfo_EM(struct LevelInfo *level, @@ -2537,6 +2794,30 @@ void CopyNativeLevel_RND_to_Native(struct LevelInfo *level) void CopyNativeLevel_Native_to_RND(struct LevelInfo *level) { + +#if 0 + { + static int ball_xy[8][2] = + { + { 0, 0 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 2, 1 }, + { 0, 2 }, + { 1, 2 }, + { 2, 2 }, + }; + int i, j; + + printf("::: A6\n"); + for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) + for (j = 0; j < 8; j++) + printf("::: ball %d, %d: %d\n", i, j, + level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]); + } +#endif + if (level->game_engine_type == GAME_ENGINE_TYPE_EM) CopyNativeLevel_EM_to_RND(level); } @@ -2919,10 +3200,15 @@ void LoadLevelFromFileInfo(struct LevelInfo *level, if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN) level->game_engine_type = GAME_ENGINE_TYPE_RND; +#if 1 + if (level_file_info->type != LEVEL_FILE_TYPE_RND) + CopyNativeLevel_Native_to_RND(level); +#else if (level_file_info->type == LEVEL_FILE_TYPE_RND) CopyNativeLevel_RND_to_Native(level); else CopyNativeLevel_Native_to_RND(level); +#endif } void LoadLevelFromFilename(struct LevelInfo *level, char *filename) @@ -2944,6 +3230,15 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) if (leveldir_current == NULL) /* only when dumping level */ return; + /* all engine modifications also valid for levels which use latest engine */ +#if 1 + if (level->game_version < VERSION_IDENT(3,2,0,5)) + { + /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */ + level->score[SC_TIME_BONUS] /= 10; + } +#endif + if (leveldir_current->latest_engine) { /* ---------- use latest game engine ----------------------------------- */ @@ -2985,7 +3280,7 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) /* player was faster than enemies in 1.0.0 and before */ if (level->file_version == FILE_VERSION_1_0) - level->double_speed = TRUE; + level->initial_player_stepsize = STEPSIZE_FAST; /* default behaviour for EM style gems was "slippery" only in 2.0.1 */ if (level->game_version == VERSION_IDENT(2,0,1,0)) @@ -3006,8 +3301,10 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) /* extra time score was same value as time left score before 3.2.0-5 */ level->extra_time_score = level->score[SC_TIME_BONUS]; +#if 0 /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */ level->score[SC_TIME_BONUS] /= 10; +#endif } /* only few elements were able to actively move into acid before 3.1.0 */ @@ -3210,6 +3507,21 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename) SetBorderElement(); } +static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename) +{ + struct LevelFileInfo *level_file_info = &level->file_info; + +#if 1 + if (level_file_info->type == LEVEL_FILE_TYPE_RND) + CopyNativeLevel_RND_to_Native(level); +#else + if (level_file_info->type == LEVEL_FILE_TYPE_RND) + CopyNativeLevel_RND_to_Native(level); + else + CopyNativeLevel_Native_to_RND(level); +#endif +} + void LoadLevelTemplate(int nr) { char *filename; @@ -3240,6 +3552,8 @@ void LoadLevel(int nr) LoadLevel_InitVersion(&level, filename); LoadLevel_InitElements(&level, filename); LoadLevel_InitPlayfield(&level, filename); + + LoadLevel_InitNativeEngines(&level, filename); } static void SaveLevel_VERS(FILE *file, struct LevelInfo *level) @@ -3274,7 +3588,7 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level) putFile8Bit(file, level->time_wheel); putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content)); - putFile8Bit(file, (level->double_speed ? 1 : 0)); + putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0)); putFile8Bit(file, (level->initial_gravity ? 1 : 0)); putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0)); putFile8Bit(file, (level->em_slippery_gems ? 1 : 0)); @@ -3418,6 +3732,20 @@ static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level, { int element = EL_CUSTOM_START + i; +#if 1 + struct ElementInfo *ei = &element_info[element]; + + if (ei->properties[EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT) + { + if (check < num_changed_custom_elements) + { + putFile16BitBE(file, element); + putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]); + } + + check++; + } +#else if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT) { if (check < num_changed_custom_elements) @@ -3428,6 +3756,7 @@ static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level, check++; } +#endif } if (check != num_changed_custom_elements) /* should not happen */ @@ -3486,7 +3815,11 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level, for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++) putFile8Bit(file, ei->description[j]); +#if 1 + putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]); +#else putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]); +#endif /* some free bytes for future properties and padding */ WriteUnusedBytesToFile(file, 7); @@ -3559,7 +3892,11 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++) putFile8Bit(file, ei->description[i]); +#if 1 + putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]); +#else putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]); +#endif WriteUnusedBytesToFile(file, 4); /* reserved for more base properties */ putFile8Bit(file, ei->num_change_pages); @@ -3720,9 +4057,39 @@ static int SaveLevel_CONF_Value(FILE *file, int pos) return num_bytes; } -static int SaveLevel_CONF_Content(FILE *file, int pos, int num_contents) +static int SaveLevel_CONF_Elements(FILE *file, int pos) +{ + int *element_array = (int *)(element_conf[pos].value); + int num_elements = *(int *)element_conf[pos].num_entities; + int default_value = element_conf[pos].default_value; + int element = element_conf[pos].element; + int type = element_conf[pos].type; + int num_bytes = 0; + boolean modified = FALSE; + int i; + + /* check if any settings have been modified before saving them */ + for (i = 0; i < num_elements; i++) + if (element_array[i] != default_value) + modified = TRUE; + + if (!modified) /* do not save unmodified default settings */ + return 0; + + num_bytes += putFile16BitBE(file, element); + num_bytes += putFile8Bit(file, type); + num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES); + + for (i = 0; i < num_elements; i++) + num_bytes += putFile16BitBE(file, element_array[i]); + + return num_bytes; +} + +static int SaveLevel_CONF_Contents(FILE *file, int pos) { struct Content *content = (struct Content *)(element_conf[pos].value); + int num_contents = *(int *)element_conf[pos].num_entities; int default_value = element_conf[pos].default_value; int element = element_conf[pos].element; int type = element_conf[pos].type; @@ -3766,8 +4133,10 @@ static int SaveLevel_CONF(FILE *file, struct LevelInfo *level) if (bytes != CONF_MASK_MULTI_BYTES) chunk_size += SaveLevel_CONF_Value(file, i); - else if (type == CONF_VALUE_CONTENT_8) - chunk_size += SaveLevel_CONF_Content(file, i, MAX_ELEMENT_CONTENTS); + else if (type == CONF_VALUE_ELEMENTS) + chunk_size += SaveLevel_CONF_Elements(file, i); + else if (type == CONF_VALUE_CONTENTS) + chunk_size += SaveLevel_CONF_Contents(file, i); } return chunk_size; @@ -3942,7 +4311,7 @@ void DumpLevel(struct LevelInfo *level) printf("Amoeba speed: %d\n", level->amoeba_speed); printf("\n"); printf("Initial gravity: %s\n", (level->initial_gravity ? "yes" : "no")); - printf("Double speed movement: %s\n", (level->double_speed ? "yes" : "no")); + printf("Initial player stepsize: %d\n", level->initial_player_stepsize); printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no")); printf("Player blocks last field: %s\n", (level->block_last_field ? "yes" : "no")); printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no")); @@ -4400,6 +4769,7 @@ void SaveTape(int nr) void DumpTape(struct TapeInfo *tape) { + int tape_frame_counter; int i, j; if (tape->no_valid_file) @@ -4417,12 +4787,14 @@ void DumpTape(struct TapeInfo *tape) printf("Level series identifier: '%s'\n", tape->level_identifier); printf_line("-", 79); + tape_frame_counter = 0; + for (i = 0; i < tape->length; i++) { if (i >= MAX_TAPE_LEN) break; - printf("%03d: ", i); + printf("%04d: ", i); for (j = 0; j < MAX_PLAYERS; j++) { @@ -4441,7 +4813,10 @@ void DumpTape(struct TapeInfo *tape) } } - printf("(%03d)\n", tape->pos[i].delay); + printf("(%03d) ", tape->pos[i].delay); + printf("[%05d]\n", tape_frame_counter); + + tape_frame_counter += tape->pos[i].delay; } printf_line("-", 79); @@ -4554,14 +4929,15 @@ void SaveScore(int nr) #define SETUP_TOKEN_TIME_LIMIT 14 #define SETUP_TOKEN_FULLSCREEN 15 #define SETUP_TOKEN_ASK_ON_ESCAPE 16 -#define SETUP_TOKEN_GRAPHICS_SET 17 -#define SETUP_TOKEN_SOUNDS_SET 18 -#define SETUP_TOKEN_MUSIC_SET 19 -#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 20 -#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 21 -#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 22 +#define SETUP_TOKEN_QUICK_SWITCH 17 +#define SETUP_TOKEN_GRAPHICS_SET 18 +#define SETUP_TOKEN_SOUNDS_SET 19 +#define SETUP_TOKEN_MUSIC_SET 20 +#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 21 +#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 22 +#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 23 -#define NUM_GLOBAL_SETUP_TOKENS 23 +#define NUM_GLOBAL_SETUP_TOKENS 24 /* editor setup */ #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH 0 @@ -4664,6 +5040,7 @@ static struct TokenInfo global_setup_tokens[] = { TYPE_SWITCH, &si.time_limit, "time_limit" }, { TYPE_SWITCH, &si.fullscreen, "fullscreen" }, { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" }, + { TYPE_SWITCH, &si.quick_switch, "quick_player_switch" }, { TYPE_STRING, &si.graphics_set, "graphics_set" }, { TYPE_STRING, &si.sounds_set, "sounds_set" }, { TYPE_STRING, &si.music_set, "music_set" }, @@ -4784,6 +5161,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->time_limit = TRUE; si->fullscreen = FALSE; si->ask_on_escape = TRUE; + si->quick_switch = FALSE; si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR); si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR); @@ -5586,7 +5964,7 @@ void LoadHelpAnimInfo() i_to_a(element_action_info[i].value)); /* do not store direction index (bit) here, but direction value! */ - for (i = 0; i < NUM_DIRECTIONS; i++) + for (i = 0; i < NUM_DIRECTIONS_FULL; i++) setHashEntry(direction_hash, element_direction_info[i].suffix, i_to_a(1 << element_direction_info[i].value)); @@ -5748,7 +6126,8 @@ void LoadHelpAnimInfo() #if 0 for (i = 0; i < num_list_entries; i++) - printf("::: %d, %d, %d => %d\n", + printf("::: '%s': %d, %d, %d => %d\n", + EL_NAME(helpanim_info[i].element), helpanim_info[i].element, helpanim_info[i].action, helpanim_info[i].direction,