#define TAPE_HEADER_SIZE 20 /* size of tape file header */
#define TAPE_HEADER_UNUSED 3 /* unused tape header bytes */
-#define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x))
-#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
-#define LEVEL_CHUNK_CUS4_SIZE(x) (96 + (x) * 48)
+#define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x))
+#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
+#define LEVEL_CHUNK_CUS4_SIZE(x) (96 + (x) * 48)
/* file identifier strings */
-#define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
-#define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
-#define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
+#define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
+#define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
+#define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
/* values for "CONF" chunk */
-#define CONF_MASK_1_BYTE 0x00
-#define CONF_MASK_2_BYTE 0x40
-#define CONF_MASK_4_BYTE 0x80
-#define CONF_MASK_MULTI_BYTES 0xc0
-
-#define CONF_MASK_BYTES 0xc0
-#define CONF_MASK_TOKEN 0x3f
-
-#define CONF_LAST_ENTRY (CONF_MASK_1_BYTE | 0)
-
-#define CONF_VALUE_INTEGER_1 (CONF_MASK_1_BYTE | 1)
-#define CONF_VALUE_INTEGER_2 (CONF_MASK_1_BYTE | 2)
-#define CONF_VALUE_INTEGER_3 (CONF_MASK_1_BYTE | 3)
-#define CONF_VALUE_INTEGER_4 (CONF_MASK_1_BYTE | 4)
-#define CONF_VALUE_BOOLEAN_1 (CONF_MASK_1_BYTE | 5)
-#define CONF_VALUE_BOOLEAN_2 (CONF_MASK_1_BYTE | 6)
-#define CONF_VALUE_BOOLEAN_3 (CONF_MASK_1_BYTE | 7)
-#define CONF_VALUE_BOOLEAN_4 (CONF_MASK_1_BYTE | 8)
-
-#define CONF_VALUE_ELEMENT_1 (CONF_MASK_2_BYTE | 1)
-#define CONF_VALUE_ELEMENT_2 (CONF_MASK_2_BYTE | 2)
-#define CONF_VALUE_ELEMENT_3 (CONF_MASK_2_BYTE | 3)
-#define CONF_VALUE_ELEMENT_4 (CONF_MASK_2_BYTE | 4)
-
-#define CONF_VALUE_CONTENT_1 (CONF_MASK_MULTI_BYTES | 1)
-#define CONF_VALUE_CONTENT_8 (CONF_MASK_MULTI_BYTES | 2)
-
-#define CONF_VALUE_INTEGER(x) ((x) >= CONF_VALUE_INTEGER_1 && \
- (x) <= CONF_VALUE_INTEGER_4)
-
-#define CONF_VALUE_BOOLEAN(x) ((x) >= CONF_VALUE_BOOLEAN_1 && \
- (x) <= CONF_VALUE_BOOLEAN_4)
-
-#define CONF_VALUE_NUM_BYTES(x) ((x) == CONF_MASK_1_BYTE ? 1 : \
- (x) == CONF_MASK_2_BYTE ? 2 : \
- (x) == CONF_MASK_4_BYTE ? 4 : 0)
+#define CONF_MASK_1_BYTE 0x00
+#define CONF_MASK_2_BYTE 0x40
+#define CONF_MASK_4_BYTE 0x80
+#define CONF_MASK_MULTI_BYTES 0xc0
+
+#define CONF_MASK_BYTES 0xc0
+#define CONF_MASK_TOKEN 0x3f
+
+#define CONF_LAST_ENTRY (CONF_MASK_1_BYTE | 0)
+
+#define CONF_VALUE_INTEGER_1 (CONF_MASK_1_BYTE | 1)
+#define CONF_VALUE_INTEGER_2 (CONF_MASK_1_BYTE | 2)
+#define CONF_VALUE_INTEGER_3 (CONF_MASK_1_BYTE | 3)
+#define CONF_VALUE_INTEGER_4 (CONF_MASK_1_BYTE | 4)
+#define CONF_VALUE_INTEGER_5 (CONF_MASK_1_BYTE | 5)
+#define CONF_VALUE_INTEGER_6 (CONF_MASK_1_BYTE | 6)
+#define CONF_VALUE_INTEGER_7 (CONF_MASK_1_BYTE | 7)
+#define CONF_VALUE_INTEGER_8 (CONF_MASK_1_BYTE | 8)
+#define CONF_VALUE_BOOLEAN_1 (CONF_MASK_1_BYTE | 9)
+#define CONF_VALUE_BOOLEAN_2 (CONF_MASK_1_BYTE | 10)
+#define CONF_VALUE_BOOLEAN_3 (CONF_MASK_1_BYTE | 11)
+#define CONF_VALUE_BOOLEAN_4 (CONF_MASK_1_BYTE | 12)
+#define CONF_VALUE_BOOLEAN_5 (CONF_MASK_1_BYTE | 13)
+#define CONF_VALUE_BOOLEAN_6 (CONF_MASK_1_BYTE | 14)
+#define CONF_VALUE_BOOLEAN_7 (CONF_MASK_1_BYTE | 15)
+#define CONF_VALUE_BOOLEAN_8 (CONF_MASK_1_BYTE | 16)
+
+#define CONF_VALUE_ELEMENT_1 (CONF_MASK_2_BYTE | 1)
+#define CONF_VALUE_ELEMENT_2 (CONF_MASK_2_BYTE | 2)
+#define CONF_VALUE_ELEMENT_3 (CONF_MASK_2_BYTE | 3)
+#define CONF_VALUE_ELEMENT_4 (CONF_MASK_2_BYTE | 4)
+#define CONF_VALUE_ELEMENT_5 (CONF_MASK_2_BYTE | 5)
+#define CONF_VALUE_ELEMENT_6 (CONF_MASK_2_BYTE | 6)
+#define CONF_VALUE_ELEMENT_7 (CONF_MASK_2_BYTE | 7)
+#define CONF_VALUE_ELEMENT_8 (CONF_MASK_2_BYTE | 8)
+
+#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)
+
+#define CONF_VALUE_BOOLEAN(x) ((x) >= CONF_VALUE_BOOLEAN_1 && \
+ (x) <= CONF_VALUE_BOOLEAN_8)
+
+#define CONF_VALUE_NUM_BYTES(x) ((x) == CONF_MASK_1_BYTE ? 1 : \
+ (x) == CONF_MASK_2_BYTE ? 2 : \
+ (x) == CONF_MASK_4_BYTE ? 4 : 0)
#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
EL_EMC_ANDROID, CONF_VALUE_INTEGER_2,
&li.android_clone_time, 10
},
- {
- EL_EMC_MAGIC_BALL, CONF_VALUE_INTEGER_1,
- &li.ball_time, 10
- },
{
EL_EMC_LENSES, CONF_VALUE_INTEGER_1,
&li.lenses_score, 10
EL_EXTRA_TIME, CONF_VALUE_INTEGER_1,
&li.extra_time, 10
},
+ {
+ EL_EXTRA_TIME, CONF_VALUE_INTEGER_2,
+ &li.extra_time_score, 10
+ },
{
EL_TIME_ORB_FULL, CONF_VALUE_INTEGER_1,
&li.time_orb_time, 10
&li.use_start_element[0], FALSE
},
{
- EL_PLAYER_2, CONF_VALUE_ELEMENT_2,
+ EL_PLAYER_2, CONF_VALUE_BOOLEAN_2,
&li.use_start_element[1], FALSE
},
{
- EL_PLAYER_3, CONF_VALUE_ELEMENT_2,
+ EL_PLAYER_3, CONF_VALUE_BOOLEAN_2,
&li.use_start_element[2], FALSE
},
{
- EL_PLAYER_4, CONF_VALUE_ELEMENT_2,
+ EL_PLAYER_4, CONF_VALUE_BOOLEAN_2,
&li.use_start_element[3], FALSE
},
+ {
+ EL_PLAYER_1, CONF_VALUE_BOOLEAN_3,
+ &li.use_artwork_element[0], FALSE
+ },
+ {
+ EL_PLAYER_2, CONF_VALUE_BOOLEAN_3,
+ &li.use_artwork_element[1], FALSE
+ },
+ {
+ EL_PLAYER_3, CONF_VALUE_BOOLEAN_3,
+ &li.use_artwork_element[2], FALSE
+ },
+ {
+ EL_PLAYER_4, CONF_VALUE_BOOLEAN_3,
+ &li.use_artwork_element[3], FALSE
+ },
+ {
+ EL_PLAYER_1, CONF_VALUE_BOOLEAN_4,
+ &li.use_explosion_element[0], FALSE
+ },
+ {
+ EL_PLAYER_2, CONF_VALUE_BOOLEAN_4,
+ &li.use_explosion_element[1], FALSE
+ },
+ {
+ EL_PLAYER_3, CONF_VALUE_BOOLEAN_4,
+ &li.use_explosion_element[2], FALSE
+ },
+ {
+ EL_PLAYER_4, CONF_VALUE_BOOLEAN_4,
+ &li.use_explosion_element[3], FALSE
+ },
+ {
+ EL_PLAYER_1, CONF_VALUE_BOOLEAN_5,
+ &li.continuous_snapping, TRUE
+ },
+ {
+ EL_PLAYER_1, CONF_VALUE_INTEGER_1,
+ &li.initial_player_stepsize, STEPSIZE_NORMAL
+ },
+ {
+ EL_EMC_MAGIC_BALL, CONF_VALUE_INTEGER_1,
+ &li.ball_time, 10
+ },
+ {
+ EL_EMC_MAGIC_BALL, CONF_VALUE_BOOLEAN_1,
+ &li.ball_random, FALSE
+ },
+ {
+ EL_EMC_MAGIC_BALL, CONF_VALUE_BOOLEAN_2,
+ &li.ball_state_initial, FALSE
+ },
/* ---------- 2-byte values ---------------------------------------------- */
+
{
EL_PLAYER_1, CONF_VALUE_ELEMENT_1,
&li.start_element[0], EL_PLAYER_1
EL_PLAYER_4, CONF_VALUE_ELEMENT_1,
&li.start_element[3], EL_PLAYER_4
},
+ {
+ EL_PLAYER_1, CONF_VALUE_ELEMENT_2,
+ &li.artwork_element[0], EL_PLAYER_1
+ },
+ {
+ EL_PLAYER_2, CONF_VALUE_ELEMENT_2,
+ &li.artwork_element[1], EL_PLAYER_2
+ },
+ {
+ EL_PLAYER_3, CONF_VALUE_ELEMENT_2,
+ &li.artwork_element[2], EL_PLAYER_3
+ },
+ {
+ EL_PLAYER_4, CONF_VALUE_ELEMENT_2,
+ &li.artwork_element[3], EL_PLAYER_4
+ },
+ {
+ EL_PLAYER_1, CONF_VALUE_ELEMENT_3,
+ &li.explosion_element[0], EL_PLAYER_1
+ },
+ {
+ EL_PLAYER_2, CONF_VALUE_ELEMENT_3,
+ &li.explosion_element[1], EL_PLAYER_2
+ },
+ {
+ EL_PLAYER_3, CONF_VALUE_ELEMENT_3,
+ &li.explosion_element[2], EL_PLAYER_3
+ },
+ {
+ EL_PLAYER_4, CONF_VALUE_ELEMENT_3,
+ &li.explosion_element[3], EL_PLAYER_4
+ },
/* ---------- 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,
},
};
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 */
static boolean clipboard_elements_initialized = FALSE;
int i, j, x, y;
+#if 1
+ InitElementPropertiesStatic();
+#endif
+
setLevelInfoToDefaultsFromConfigList(level);
setLevelInfoToDefaults_EM();
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;
level->can_pass_to_walkable = FALSE;
level->grow_into_diggable = TRUE;
+#if 0
level->block_snap_field = TRUE;
+#endif
level->block_last_field = FALSE; /* EM does not block by default */
level->sp_block_last_field = TRUE; /* SP blocks the last field */
level->magnify_time = 10;
level->slurp_score = 10;
level->wind_direction_initial = MV_NONE;
-#endif
level->ball_random = FALSE;
level->ball_state_initial = FALSE;
-#if 0
for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
for (x = 0; x < 3; x++)
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;
}
for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
- level->score[i] = 10;
+ level->score[i] = (i == SC_TIME_BONUS ? 1 : 10);
level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
ei->current_change_page = 0;
+#if 0
+ /* !!! 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 */
SET_PROPERTY(element, EP_CAN_MOVE_INTO_ACID, TRUE);
return;
/* try to determine better author name than 'anonymous' */
- if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
+ if (!strEqual(leveldir_current->author, ANONYMOUS_NAME))
{
strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
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)
{
char *id_lower = getStringToLower(filetype_id_list[i].id);
- if (strcmp(filetype_id_lower, id_lower) == 0)
+ if (strEqual(filetype_id_lower, id_lower))
filetype = filetype_id_list[i].filetype;
free(id_lower);
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);
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;
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);
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);
/* always start with reliable default values */
setElementChangeInfoToDefaults(change);
+ /* bits 0 - 31 of "has_event[]" ... */
event_bits = getFile32BitBE(file);
- for (j = 0; j < NUM_CHANGE_EVENTS; j++)
+ for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
if (event_bits & (1 << j))
change->has_event[j] = TRUE;
change->action_mode = getFile8Bit(file);
change->action_arg = getFile16BitBE(file);
- /* some free bytes for future change property values and padding */
- ReadUnusedBytesFromFile(file, 1);
+ /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
+ event_bits = getFile8Bit(file);
+ for (j = 32; j < NUM_CHANGE_EVENTS; j++)
+ if (event_bits & (1 << (j - 32)))
+ change->has_event[j] = TRUE;
}
/* mark this custom element as modified */
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;
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) :
}
getFileChunkBE(file, chunk_name, NULL);
- if (strcmp(chunk_name, "RND1") == 0)
+ if (strEqual(chunk_name, "RND1"))
{
getFile32BitBE(file); /* not used */
getFileChunkBE(file, chunk_name, NULL);
- if (strcmp(chunk_name, "CAVE") != 0)
+ if (!strEqual(chunk_name, "CAVE"))
{
level->no_valid_file = TRUE;
int i = 0;
while (chunk_info[i].name != NULL &&
- strcmp(chunk_name, chunk_info[i].name) != 0)
+ !strEqual(chunk_name, chunk_info[i].name))
i++;
if (chunk_info[i].name == NULL)
};
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);
lev->ball_random = level->ball_random;
lev->ball_state_initial = level->ball_state_initial;
lev->ball_time = level->ball_time;
+ lev->num_ball_arrays = level->num_ball_contents;
lev->lenses_score = level->lenses_score;
lev->magnify_score = level->magnify_score;
lev->lenses_time = level->lenses_time;
lev->magnify_time = level->magnify_time;
- lev->wind_direction_initial = level->wind_direction_initial;
+
+ lev->wind_direction_initial =
+ map_direction_RND_to_EM(level->wind_direction_initial);
+ lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
+ lev->wind_time : 0);
for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
for (j = 0; j < 8; j++)
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++)
{
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]))
+ {
+ ply1->x_initial = x + 1;
+ ply1->y_initial = y + 1;
+ level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
+ }
+#else
+ /* !!! ADD SUPPORT FOR MORE THAN ONE PLAYER !!! */
if (level->field[x][y] == EL_PLAYER_1)
{
ply1->x_initial = x + 1;
ply2->y_initial = y + 1;
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
}
}
};
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);
level->ball_random = lev->ball_random;
level->ball_state_initial = lev->ball_state_initial;
level->ball_time = lev->ball_time;
+ level->num_ball_contents = lev->num_ball_arrays;
level->lenses_score = lev->lenses_score;
level->magnify_score = lev->magnify_score;
level->lenses_time = lev->lenses_time;
level->magnify_time = lev->magnify_time;
- level->wind_direction_initial = lev->wind_direction_initial;
+
+ 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++)
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,
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);
}
level->time_wheel = 0;
level->amoeba_content = EL_EMPTY;
+#if 1
+ /* original Supaplex does not use score values -- use default values */
+#else
for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
level->score[i] = 0; /* !!! CORRECT THIS !!! */
+#endif
/* there are no yamyams in supaplex levels */
for (i = 0; i < level->num_yamyam_contents; i++)
if (reading_multipart_level &&
(!is_multipart_level ||
- strcmp(level->name, multipart_level.name) != 0))
+ !strEqual(level->name, multipart_level.name)))
{
/* we are already reading parts of a multi-part level, but this level is
either not a multi-part level, or a part of a different multi-part
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)
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 0
+ leveldir_current->latest_engine = TRUE; /* !!! TEST ONLY !!! */
+#endif
+
if (leveldir_current->latest_engine)
{
/* ---------- use latest game engine ----------------------------------- */
/* 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))
if (level->game_version < VERSION_IDENT(2,2,0,0))
level->use_spring_bug = TRUE;
- /* time orb caused limited time in endless time levels before 3.2.0-5 */
if (level->game_version < VERSION_IDENT(3,2,0,5))
+ {
+ /* time orb caused limited time in endless time levels before 3.2.0-5 */
level->use_time_orb_bug = TRUE;
- /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
- if (level->game_version < VERSION_IDENT(3,2,0,5))
+ /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
level->block_snap_field = FALSE;
+ /* 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
+ }
+
+ if (level->game_version < VERSION_IDENT(3,2,0,7))
+ {
+ /* default behaviour for snapping was "not continuous" before 3.2.0-7 */
+ level->continuous_snapping = FALSE;
+ }
+
/* only few elements were able to actively move into acid before 3.1.0 */
/* trigger settings did not exist before 3.1.0; set to default "any" */
if (level->game_version < VERSION_IDENT(3,1,0,0))
int element = EL_CUSTOM_START + i;
/* order of checking and copying events to be mapped is important */
+ /* (do not change the start and end value -- they are constant) */
for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
{
if (HAS_CHANGE_EVENT(element, j - 2))
}
/* order of checking and copying events to be mapped is important */
+ /* (do not change the start and end value -- they are constant) */
for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
{
if (HAS_CHANGE_EVENT(element, j - 1))
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;
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)
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));
{
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)
check++;
}
+#endif
}
if (check != num_changed_custom_elements) /* should not happen */
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);
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);
for (i = 0; i < ei->num_change_pages; i++)
{
struct ElementChangeInfo *change = &ei->change_page[i];
- unsigned long event_bits = 0;
+ unsigned long event_bits;
- for (j = 0; j < NUM_CHANGE_EVENTS; j++)
+ /* bits 0 - 31 of "has_event[]" ... */
+ event_bits = 0;
+ for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
if (change->has_event[j])
event_bits |= (1 << j);
-
putFile32BitBE(file, event_bits);
putFile16BitBE(file, change->target_element);
putFile8Bit(file, change->action_mode);
putFile16BitBE(file, change->action_arg);
- /* some free bytes for future change property values and padding */
- WriteUnusedBytesToFile(file, 1);
+ /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
+ event_bits = 0;
+ for (j = 32; j < NUM_CHANGE_EVENTS; j++)
+ if (change->has_event[j])
+ event_bits |= (1 << (j - 32));
+ putFile8Bit(file, event_bits);
}
}
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;
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;
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"));
}
getFileChunkBE(file, chunk_name, NULL);
- if (strcmp(chunk_name, "RND1") == 0)
+ if (strEqual(chunk_name, "RND1"))
{
getFile32BitBE(file); /* not used */
getFileChunkBE(file, chunk_name, NULL);
- if (strcmp(chunk_name, "TAPE") != 0)
+ if (!strEqual(chunk_name, "TAPE"))
{
tape.no_valid_file = TRUE;
int i = 0;
while (chunk_info[i].name != NULL &&
- strcmp(chunk_name, chunk_info[i].name) != 0)
+ !strEqual(chunk_name, chunk_info[i].name))
i++;
if (chunk_info[i].name == NULL)
void DumpTape(struct TapeInfo *tape)
{
+ int tape_frame_counter;
int i, j;
if (tape->no_valid_file)
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++)
{
}
}
- 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);
#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 NUM_GLOBAL_SETUP_TOKENS 23
+#define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR 17
+#define SETUP_TOKEN_QUICK_SWITCH 18
+#define SETUP_TOKEN_INPUT_ON_FOCUS 19
+#define SETUP_TOKEN_PREFER_AGA_GRAPHICS 20
+#define SETUP_TOKEN_GRAPHICS_SET 21
+#define SETUP_TOKEN_SOUNDS_SET 22
+#define SETUP_TOKEN_MUSIC_SET 23
+#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 24
+#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 25
+#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 26
+
+#define NUM_GLOBAL_SETUP_TOKENS 27
/* editor setup */
#define SETUP_TOKEN_EDITOR_EL_BOULDERDASH 0
#define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH 7
#define SETUP_TOKEN_EDITOR_EL_CHARS 8
#define SETUP_TOKEN_EDITOR_EL_CUSTOM 9
-#define SETUP_TOKEN_EDITOR_EL_CUSTOM_MORE 10
-#define SETUP_TOKEN_EDITOR_EL_HEADLINES 11
-#define SETUP_TOKEN_EDITOR_EL_USER_DEFINED 12
+#define SETUP_TOKEN_EDITOR_EL_HEADLINES 10
+#define SETUP_TOKEN_EDITOR_EL_USER_DEFINED 11
+#define SETUP_TOKEN_EDITOR_EL_DYNAMIC 12
#define NUM_EDITOR_SETUP_TOKENS 13
+/* editor cascade setup */
+#define SETUP_TOKEN_EDITOR_CASCADE_BD 0
+#define SETUP_TOKEN_EDITOR_CASCADE_EM 1
+#define SETUP_TOKEN_EDITOR_CASCADE_EMC 2
+#define SETUP_TOKEN_EDITOR_CASCADE_RND 3
+#define SETUP_TOKEN_EDITOR_CASCADE_SB 4
+#define SETUP_TOKEN_EDITOR_CASCADE_SP 5
+#define SETUP_TOKEN_EDITOR_CASCADE_DC 6
+#define SETUP_TOKEN_EDITOR_CASCADE_DX 7
+#define SETUP_TOKEN_EDITOR_CASCADE_TEXT 8
+#define SETUP_TOKEN_EDITOR_CASCADE_CE 9
+#define SETUP_TOKEN_EDITOR_CASCADE_GE 10
+#define SETUP_TOKEN_EDITOR_CASCADE_USER 11
+#define SETUP_TOKEN_EDITOR_CASCADE_GENERIC 12
+#define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC 13
+
+#define NUM_EDITOR_CASCADE_SETUP_TOKENS 14
+
/* shortcut setup */
#define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0
#define SETUP_TOKEN_SHORTCUT_LOAD_GAME 1
#define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE 2
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1 3
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2 4
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3 5
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4 6
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL 7
-#define NUM_SHORTCUT_SETUP_TOKENS 3
+#define NUM_SHORTCUT_SETUP_TOKENS 8
/* player setup */
#define SETUP_TOKEN_PLAYER_USE_JOYSTICK 0
static struct SetupInfo si;
static struct SetupEditorInfo sei;
+static struct SetupEditorCascadeInfo seci;
static struct SetupShortcutInfo ssi;
static struct SetupInputInfo sii;
static struct SetupSystemInfo syi;
{ TYPE_SWITCH, &si.time_limit, "time_limit" },
{ TYPE_SWITCH, &si.fullscreen, "fullscreen" },
{ TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
+ { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor" },
+ { TYPE_SWITCH, &si.quick_switch, "quick_player_switch" },
+ { TYPE_SWITCH, &si.input_on_focus, "input_on_focus" },
+ { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics" },
{ TYPE_STRING, &si.graphics_set, "graphics_set" },
{ TYPE_STRING, &si.sounds_set, "sounds_set" },
{ TYPE_STRING, &si.music_set, "music_set" },
{ TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash" },
{ TYPE_SWITCH, &sei.el_chars, "editor.el_chars" },
{ TYPE_SWITCH, &sei.el_custom, "editor.el_custom" },
- { TYPE_SWITCH, &sei.el_custom_more, "editor.el_custom_more" },
{ TYPE_SWITCH, &sei.el_headlines, "editor.el_headlines" },
{ TYPE_SWITCH, &sei.el_user_defined, "editor.el_user_defined" },
+ { TYPE_SWITCH, &sei.el_dynamic, "editor.el_dynamic" },
+};
+
+static struct TokenInfo editor_cascade_setup_tokens[] =
+{
+ { TYPE_SWITCH, &seci.el_bd, "editor.cascade.el_bd" },
+ { TYPE_SWITCH, &seci.el_em, "editor.cascade.el_em" },
+ { TYPE_SWITCH, &seci.el_emc, "editor.cascade.el_emc" },
+ { TYPE_SWITCH, &seci.el_rnd, "editor.cascade.el_rnd" },
+ { TYPE_SWITCH, &seci.el_sb, "editor.cascade.el_sb" },
+ { TYPE_SWITCH, &seci.el_sp, "editor.cascade.el_sp" },
+ { TYPE_SWITCH, &seci.el_dc, "editor.cascade.el_dc" },
+ { TYPE_SWITCH, &seci.el_dx, "editor.cascade.el_dx" },
+ { TYPE_SWITCH, &seci.el_chars, "editor.cascade.el_chars" },
+ { TYPE_SWITCH, &seci.el_ce, "editor.cascade.el_ce" },
+ { TYPE_SWITCH, &seci.el_ge, "editor.cascade.el_ge" },
+ { TYPE_SWITCH, &seci.el_user, "editor.cascade.el_user" },
+ { TYPE_SWITCH, &seci.el_dynamic, "editor.cascade.el_dynamic" },
};
static struct TokenInfo shortcut_setup_tokens[] =
{
{ TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
{ TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
- { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }
+ { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" },
+ { TYPE_KEY_X11, &ssi.focus_player[0], "shortcut.focus_player_1" },
+ { TYPE_KEY_X11, &ssi.focus_player[1], "shortcut.focus_player_2" },
+ { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3" },
+ { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4" },
+ { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all" },
};
static struct TokenInfo player_setup_tokens[] =
{ TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
{ TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
{ TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
- { TYPE_KEY_X11, &sii.key.drop, ".key.place_bomb" }
+ { TYPE_KEY_X11, &sii.key.drop, ".key.place_bomb" },
};
static struct TokenInfo system_setup_tokens[] =
{
{ TYPE_STRING, &syi.sdl_audiodriver, "system.sdl_audiodriver" },
- { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }
+ { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" },
};
static struct TokenInfo options_setup_tokens[] =
{
- { TYPE_BOOLEAN, &soi.verbose, "options.verbose" }
+ { TYPE_BOOLEAN, &soi.verbose, "options.verbose" },
};
static char *get_corrected_login_name(char *login_name)
si->time_limit = TRUE;
si->fullscreen = FALSE;
si->ask_on_escape = TRUE;
+ si->ask_on_escape_editor = TRUE;
+ si->quick_switch = FALSE;
+ si->input_on_focus = FALSE;
+ si->prefer_aga_graphics = TRUE;
si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
si->editor.el_dx_boulderdash = TRUE;
si->editor.el_chars = TRUE;
si->editor.el_custom = TRUE;
- si->editor.el_custom_more = FALSE;
si->editor.el_headlines = TRUE;
si->editor.el_user_defined = FALSE;
+ si->editor.el_dynamic = TRUE;
si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
+ si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1;
+ si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2;
+ si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3;
+ si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4;
+ si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
+
for (i = 0; i < MAX_PLAYERS; i++)
{
si->input[i].use_joystick = FALSE;
si->options.verbose = FALSE;
}
+static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
+{
+ si->editor_cascade.el_bd = TRUE;
+ si->editor_cascade.el_em = TRUE;
+ si->editor_cascade.el_emc = TRUE;
+ si->editor_cascade.el_rnd = TRUE;
+ si->editor_cascade.el_sb = TRUE;
+ si->editor_cascade.el_sp = TRUE;
+ si->editor_cascade.el_dc = TRUE;
+ si->editor_cascade.el_dx = TRUE;
+
+ si->editor_cascade.el_chars = FALSE;
+ si->editor_cascade.el_ce = FALSE;
+ si->editor_cascade.el_ge = FALSE;
+ si->editor_cascade.el_user = FALSE;
+ si->editor_cascade.el_dynamic = FALSE;
+}
+
static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
{
int i, pnr;
setup.options = soi;
}
+static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
+{
+ int i;
+
+ if (!setup_file_hash)
+ return;
+
+ /* editor cascade setup */
+ seci = setup.editor_cascade;
+ for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
+ setSetupInfo(editor_cascade_setup_tokens, i,
+ getHashEntry(setup_file_hash,
+ editor_cascade_setup_tokens[i].text));
+ setup.editor_cascade = seci;
+}
+
void LoadSetup()
{
char *filename = getSetupFilename();
{
char *player_name_new;
- checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
+ checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
decodeSetupFileHash(setup_file_hash);
setup.direct_draw = !setup.double_buffering;
Error(ERR_WARN, "using default setup values");
}
+void LoadSetup_EditorCascade()
+{
+ char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
+ SetupFileHash *setup_file_hash = NULL;
+
+ /* always start with reliable default values */
+ setSetupInfoToDefaults_EditorCascade(&setup);
+
+ setup_file_hash = loadSetupFileHash(filename);
+
+ if (setup_file_hash)
+ {
+ checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
+ decodeSetupFileHash_EditorCascade(setup_file_hash);
+
+ freeSetupFileHash(setup_file_hash);
+ }
+
+ free(filename);
+}
+
void SaveSetup()
{
char *filename = getSetupFilename();
SetFilePermissions(filename, PERMS_PRIVATE);
}
+void SaveSetup_EditorCascade()
+{
+ char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
+ FILE *file;
+ int i;
+
+ InitUserDataDirectory();
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
+ free(filename);
+ return;
+ }
+
+ fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
+ getCookie("SETUP")));
+ fprintf(file, "\n");
+
+ seci = setup.editor_cascade;
+ fprintf(file, "\n");
+ for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
+ fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+
+ free(filename);
+}
+
void LoadCustomElementDescriptions()
{
char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
/* always start with reliable default values from default config */
for (i = 0; image_config_vars[i].token != NULL; i++)
for (j = 0; image_config[j].token != NULL; j++)
- if (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
+ if (strEqual(image_config_vars[i].token, image_config[j].token))
*image_config_vars[i].value =
get_auto_parameter_value(image_config_vars[i].token,
image_config[j].value);
/* add space for up to 3 more elements for padding that may be needed */
*num_elements += 3;
+ /* free memory for old list of elements, if needed */
+ checked_free(*elements);
+
+ /* allocate memory for new list of elements */
*elements = checked_malloc(*num_elements * sizeof(int));
*num_elements = 0;
char *basename, boolean is_sound)
{
for (; list != NULL; list = list->next)
- if (list->is_sound == is_sound && strcmp(list->basename, basename) == 0)
+ if (list->is_sound == is_sound && strEqual(list->basename, basename))
return TRUE;
return FALSE;
if (music->filename == NULL)
continue;
- if (strcmp(music->filename, UNDEFINED_FILENAME) == 0)
+ if (strEqual(music->filename, UNDEFINED_FILENAME))
continue;
/* a configured file may be not recognized as music */
if (music->filename == NULL)
continue;
- if (strcmp(basename, music->filename) == 0)
+ if (strEqual(basename, music->filename))
{
music_already_used = TRUE;
break;
if (sound->filename == NULL)
continue;
- if (strcmp(sound->filename, UNDEFINED_FILENAME) == 0)
+ if (strEqual(sound->filename, UNDEFINED_FILENAME))
continue;
/* a configured file may be not recognized as sound */
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));
char *element_value, *action_value, *direction_value;
int delay = atoi(list->value);
- if (strcmp(list->token, "end") == 0)
+ if (strEqual(list->token, "end"))
{
add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
#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,