// (c) 1995-2014 by Artsoft Entertainment
// Holger Schemel
// info@artsoft.org
-// http://www.artsoft.org/
+// https://www.artsoft.org/
// ----------------------------------------------------------------------------
// files.c
// ============================================================================
#define TAPE_CHUNK_VERS_SIZE 8 // size of file version chunk
#define TAPE_CHUNK_HEAD_SIZE 20 // size of tape file header
-#define TAPE_CHUNK_HEAD_UNUSED 2 // unused tape header bytes
+#define TAPE_CHUNK_HEAD_UNUSED 1 // unused tape header bytes
+#define TAPE_CHUNK_SCRN_SIZE 2 // size of screen size chunk
+
+#define SCORE_CHUNK_VERS_SIZE 8 // size of file version chunk
#define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x))
#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
// 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 SCORE_COOKIE_TMPL "ROCKSNDIAMONDS_SCORE_FILE_VERSION_x.x"
// values for deciding when (not) to save configuration data
#define SAVE_CONF_NEVER 0
&li.solved_by_one_player, FALSE
},
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(12),
+ &li.time_score_base, 1
+ },
+
+ {
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(13),
+ &li.rate_time_over_score, FALSE
+ },
+
{
-1, -1,
-1, -1,
TYPE_BOOLEAN, CONF_VALUE_8_BIT(15),
&li.lazy_relocation, FALSE
},
+ {
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(16),
+ &li.finish_dig_collect, TRUE
+ },
// (these values are different for each player)
{
&li.android_clone_time, 10
},
{
- EL_EMC_ANDROID, -1,
+ EL_EMC_ANDROID, SAVE_CONF_NEVER,
TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1),
&li.android_clone_element[0], EL_EMPTY, NULL,
+ &li.num_android_clone_elements, 1, MAX_ANDROID_ELEMENTS_OLD
+ },
+ {
+ EL_EMC_ANDROID, -1,
+ TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(2),
+ &li.android_clone_element[0], EL_EMPTY, NULL,
&li.num_android_clone_elements, 1, MAX_ANDROID_ELEMENTS
},
{
EL_EMC_MAGIC_BALL, -1,
TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
- &li.ball_state_initial, FALSE
+ &li.ball_active_initial, FALSE
},
{
EL_EMC_MAGIC_BALL, -1,
&xx_ei.move_delay_random, 0,
&yy_ei.move_delay_random
},
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(16),
+ &xx_ei.step_delay_fixed, 0,
+ &yy_ei.step_delay_fixed
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(17),
+ &xx_ei.step_delay_random, 0,
+ &yy_ei.step_delay_random
+ },
{
-1, -1,
if ((dir = openDirectory(directory)) == NULL)
{
- Error(ERR_WARN, "cannot read current level directory '%s'", directory);
+ Warn("cannot read current level directory '%s'", directory);
return basename;
}
// functions for loading R'n'D level
// ----------------------------------------------------------------------------
-static int getMappedElement(int element)
+int getMappedElement(int element)
{
// remap some (historic, now obsolete) elements
default:
if (element >= NUM_FILE_ELEMENTS)
{
- Error(ERR_WARN, "invalid level element %d", element);
+ Warn("invalid level element %d", element);
element = EL_UNKNOWN;
}
}
else
{
- Error(ERR_WARN, "cannot load content for element '%d'", element);
+ Warn("cannot load content for element '%d'", element);
}
return chunk_size;
if (IS_CUSTOM_ELEMENT(element))
element_info[element].properties[EP_BITFIELD_BASE_NR] = properties;
else
- Error(ERR_WARN, "invalid custom element number %d", element);
+ Warn("invalid custom element number %d", element);
// older game versions that wrote level files with CUS1 chunks used
// different default push delay values (not yet stored in level file)
if (IS_CUSTOM_ELEMENT(element))
element_info[element].change->target_element = custom_target_element;
else
- Error(ERR_WARN, "invalid custom element number %d", element);
+ Warn("invalid custom element number %d", element);
}
level->file_has_custom_elements = TRUE;
if (!IS_CUSTOM_ELEMENT(element))
{
- Error(ERR_WARN, "invalid custom element number %d", element);
+ Warn("invalid custom element number %d", element);
element = EL_INTERNAL_DUMMY;
}
if (!IS_CUSTOM_ELEMENT(element))
{
- Error(ERR_WARN, "invalid custom element number %d", element);
+ Warn("invalid custom element number %d", element);
ReadUnusedBytesFromFile(file, chunk_size - 2);
+
return chunk_size;
}
if (!IS_GROUP_ELEMENT(element))
{
- Error(ERR_WARN, "invalid group element number %d", element);
+ Warn("invalid group element number %d", element);
ReadUnusedBytesFromFile(file, chunk_size - 2);
+
return chunk_size;
}
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);
+ Warn("truncating number of entities for element %d from %d to %d",
+ element, num_entities, max_num_entities);
num_entities = max_num_entities;
}
data_type == TYPE_CONTENT_LIST))
{
// for element and content lists, zero entities are not allowed
- Error(ERR_WARN, "found empty list of entities for element %d",
- element);
+ Warn("found empty list of entities for element %d", element);
// do not set "num_entities" here to prevent reading behind buffer
int error_conf_chunk_token = conf_type & CONF_MASK_TOKEN;
int error_element = real_element;
- Error(ERR_WARN, "cannot load micro chunk '%s(%d)' value for element %d ['%s']",
- error_conf_chunk_bytes, error_conf_chunk_token,
- error_element, EL_NAME(error_element));
+ Warn("cannot load micro chunk '%s(%d)' value for element %d ['%s']",
+ error_conf_chunk_bytes, error_conf_chunk_token,
+ error_element, EL_NAME(error_element));
}
return micro_chunk_size;
if (ei->num_change_pages == -1)
{
- Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
- EL_NAME(element));
+ Warn("LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
+ EL_NAME(element));
ei->num_change_pages = 1;
if (level_info_only)
return;
- Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+ Warn("cannot read level '%s' -- using empty level", filename);
if (!setup.editor.use_template_for_new_levels)
return;
{
level->no_valid_file = TRUE;
- Error(ERR_WARN, "unknown format of level file '%s'", filename);
+ Warn("unknown format of level file '%s'", filename);
closeFile(file);
{
level->no_valid_file = TRUE;
- Error(ERR_WARN, "unknown format of level file '%s'", filename);
+ Warn("unknown format of level file '%s'", filename);
closeFile(file);
{
level->no_valid_file = TRUE;
- Error(ERR_WARN, "unsupported version of level file '%s'", filename);
+ Warn("unsupported version of level file '%s'", filename);
closeFile(file);
if (chunk_info[i].name == NULL)
{
- Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
- chunk_name, filename);
+ Warn("unknown chunk '%s' in level file '%s'",
+ chunk_name, filename);
+
ReadUnusedBytesFromFile(file, chunk_size);
}
else if (chunk_info[i].size != -1 &&
chunk_info[i].size != chunk_size)
{
- Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
- chunk_size, chunk_name, filename);
+ Warn("wrong size (%d) of chunk '%s' in level file '%s'",
+ chunk_size, chunk_name, filename);
+
ReadUnusedBytesFromFile(file, chunk_size);
}
else
// information, so check them here
if (chunk_size_expected != chunk_size)
{
- Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
- chunk_size, chunk_name, filename);
+ Warn("wrong size (%d) of chunk '%s' in level file '%s'",
+ chunk_size, chunk_name, filename);
}
}
}
{ 2, 2 },
};
struct LevelInfo_EM *level_em = level->native_em_level;
- struct LEVEL *lev = level_em->lev;
- struct PLAYER **ply = level_em->ply;
+ struct CAVE *cav = level_em->cav;
int i, j, x, y;
- lev->width = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
- lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
+ cav->width = MIN(level->fieldx, MAX_PLAYFIELD_WIDTH);
+ cav->height = MIN(level->fieldy, MAX_PLAYFIELD_HEIGHT);
- lev->time_seconds = level->time;
- lev->required_initial = level->gems_needed;
+ cav->time_seconds = level->time;
+ cav->gems_needed = level->gems_needed;
- lev->emerald_score = level->score[SC_EMERALD];
- lev->diamond_score = level->score[SC_DIAMOND];
- lev->alien_score = level->score[SC_ROBOT];
- lev->tank_score = level->score[SC_SPACESHIP];
- lev->bug_score = level->score[SC_BUG];
- lev->eater_score = level->score[SC_YAMYAM];
- lev->nut_score = level->score[SC_NUT];
- lev->dynamite_score = level->score[SC_DYNAMITE];
- lev->key_score = level->score[SC_KEY];
- lev->exit_score = level->score[SC_TIME_BONUS];
+ cav->emerald_score = level->score[SC_EMERALD];
+ cav->diamond_score = level->score[SC_DIAMOND];
+ cav->alien_score = level->score[SC_ROBOT];
+ cav->tank_score = level->score[SC_SPACESHIP];
+ cav->bug_score = level->score[SC_BUG];
+ cav->eater_score = level->score[SC_YAMYAM];
+ cav->nut_score = level->score[SC_NUT];
+ cav->dynamite_score = level->score[SC_DYNAMITE];
+ cav->key_score = level->score[SC_KEY];
+ cav->exit_score = level->score[SC_TIME_BONUS];
+
+ cav->num_eater_arrays = level->num_yamyam_contents;
for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
for (y = 0; y < 3; y++)
for (x = 0; x < 3; x++)
- lev->eater_array[i][y * 3 + x] =
- map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
+ cav->eater_array[i][y * 3 + x] =
+ map_element_RND_to_EM_cave(level->yamyam_content[i].e[x][y]);
- lev->amoeba_time = level->amoeba_speed;
- lev->wonderwall_time_initial = level->time_magic_wall;
- lev->wheel_time = level->time_wheel;
+ cav->amoeba_time = level->amoeba_speed;
+ cav->wonderwall_time = level->time_magic_wall;
+ cav->wheel_time = level->time_wheel;
- lev->android_move_time = level->android_move_time;
- lev->android_clone_time = level->android_clone_time;
- 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;
+ cav->android_move_time = level->android_move_time;
+ cav->android_clone_time = level->android_clone_time;
+ cav->ball_random = level->ball_random;
+ cav->ball_active = level->ball_active_initial;
+ cav->ball_time = level->ball_time;
+ cav->num_ball_arrays = level->num_ball_contents;
- lev->lenses_score = level->lenses_score;
- lev->magnify_score = level->magnify_score;
- lev->slurp_score = level->slurp_score;
+ cav->lenses_score = level->lenses_score;
+ cav->magnify_score = level->magnify_score;
+ cav->slurp_score = level->slurp_score;
- lev->lenses_time = level->lenses_time;
- lev->magnify_time = level->magnify_time;
+ cav->lenses_time = level->lenses_time;
+ cav->magnify_time = level->magnify_time;
- lev->wind_direction_initial =
+ cav->wind_direction =
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++)
- lev->ball_array[i][j] =
- map_element_RND_to_EM(level->
- ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+ cav->ball_array[i][j] =
+ map_element_RND_to_EM_cave(level->ball_content[i].
+ e[ball_xy[j][0]][ball_xy[j][1]]);
map_android_clone_elements_RND_to_EM(level);
- // first fill the complete playfield with the default border element
+ // first fill the complete playfield with the empty space 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 (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);
- }
+ cav->cave[x][y] = Cblank;
// 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++)
+ for (y = 0; y < cav->height; y++) for (x = 0; x < cav->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;
+ int new_element = map_element_RND_to_EM_cave(level->field[x][y]);
if (level->field[x][y] == EL_AMOEBA_DEAD)
- new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
+ new_element = map_element_RND_to_EM_cave(EL_AMOEBA_WET);
- level_em->cave[xx][yy] = new_element;
+ cav->cave[x][y] = new_element;
}
for (i = 0; i < MAX_PLAYERS; i++)
{
- ply[i]->x_initial = 0;
- ply[i]->y_initial = 0;
+ cav->player_x[i] = -1;
+ cav->player_y[i] = -1;
}
// initialize player positions and delete players from the playfield
- for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
+ for (y = 0; y < cav->height; y++) for (x = 0; x < cav->width; x++)
{
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;
+ cav->player_x[player_nr] = x;
+ cav->player_y[player_nr] = y;
- level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
+ cav->cave[x][y] = map_element_RND_to_EM_cave(EL_EMPTY);
}
}
-
- if (BorderElement == EL_STEELWALL)
- {
- lev->width += 2;
- lev->height += 2;
- }
}
static void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
{ 2, 2 },
};
struct LevelInfo_EM *level_em = level->native_em_level;
- struct LEVEL *lev = level_em->lev;
- struct PLAYER **ply = level_em->ply;
+ struct CAVE *cav = level_em->cav;
int i, j, x, y;
- level->fieldx = MIN(lev->width, MAX_LEV_FIELDX);
- level->fieldy = MIN(lev->height, MAX_LEV_FIELDY);
+ level->fieldx = MIN(cav->width, MAX_LEV_FIELDX);
+ level->fieldy = MIN(cav->height, MAX_LEV_FIELDY);
- level->time = lev->time_seconds;
- level->gems_needed = lev->required_initial;
+ level->time = cav->time_seconds;
+ level->gems_needed = cav->gems_needed;
sprintf(level->name, "Level %d", level->file_info.nr);
- level->score[SC_EMERALD] = lev->emerald_score;
- level->score[SC_DIAMOND] = lev->diamond_score;
- level->score[SC_ROBOT] = lev->alien_score;
- level->score[SC_SPACESHIP] = lev->tank_score;
- level->score[SC_BUG] = lev->bug_score;
- level->score[SC_YAMYAM] = lev->eater_score;
- level->score[SC_NUT] = lev->nut_score;
- level->score[SC_DYNAMITE] = lev->dynamite_score;
- level->score[SC_KEY] = lev->key_score;
- level->score[SC_TIME_BONUS] = lev->exit_score;
+ level->score[SC_EMERALD] = cav->emerald_score;
+ level->score[SC_DIAMOND] = cav->diamond_score;
+ level->score[SC_ROBOT] = cav->alien_score;
+ level->score[SC_SPACESHIP] = cav->tank_score;
+ level->score[SC_BUG] = cav->bug_score;
+ level->score[SC_YAMYAM] = cav->eater_score;
+ level->score[SC_NUT] = cav->nut_score;
+ level->score[SC_DYNAMITE] = cav->dynamite_score;
+ level->score[SC_KEY] = cav->key_score;
+ level->score[SC_TIME_BONUS] = cav->exit_score;
- level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
+ level->num_yamyam_contents = cav->num_eater_arrays;
- for (i = 0; i < level->num_yamyam_contents; i++)
+ for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
for (y = 0; y < 3; y++)
for (x = 0; x < 3; x++)
level->yamyam_content[i].e[x][y] =
- map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
+ map_element_EM_to_RND_cave(cav->eater_array[i][y * 3 + x]);
- level->amoeba_speed = lev->amoeba_time;
- level->time_magic_wall = lev->wonderwall_time_initial;
- level->time_wheel = lev->wheel_time;
+ level->amoeba_speed = cav->amoeba_time;
+ level->time_magic_wall = cav->wonderwall_time;
+ level->time_wheel = cav->wheel_time;
- level->android_move_time = lev->android_move_time;
- level->android_clone_time = lev->android_clone_time;
- 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->android_move_time = cav->android_move_time;
+ level->android_clone_time = cav->android_clone_time;
+ level->ball_random = cav->ball_random;
+ level->ball_active_initial = cav->ball_active;
+ level->ball_time = cav->ball_time;
+ level->num_ball_contents = cav->num_ball_arrays;
- level->lenses_score = lev->lenses_score;
- level->magnify_score = lev->magnify_score;
- level->slurp_score = lev->slurp_score;
+ level->lenses_score = cav->lenses_score;
+ level->magnify_score = cav->magnify_score;
+ level->slurp_score = cav->slurp_score;
- level->lenses_time = lev->lenses_time;
- level->magnify_time = lev->magnify_time;
+ level->lenses_time = cav->lenses_time;
+ level->magnify_time = cav->magnify_time;
level->wind_direction_initial =
- map_direction_EM_to_RND(lev->wind_direction_initial);
+ map_direction_EM_to_RND(cav->wind_direction);
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]);
+ map_element_EM_to_RND_cave(cav->ball_array[i][j]);
map_android_clone_elements_EM_to_RND(level);
// convert the playfield (some elements need special treatment)
for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
{
- int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]);
+ int new_element = map_element_EM_to_RND_cave(cav->cave[x][y]);
if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0)
new_element = EL_AMOEBA_DEAD;
{
// 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;
+ int jx = cav->player_x[nr];
+ int jy = cav->player_y[nr];
if (jx != -1 && jy != -1)
level->field[jx][jy] = EL_PLAYER_1 + nr;
}
+
+ // time score is counted for each 10 seconds left in Emerald Mine levels
+ level->time_score_base = 10;
}
{
num_invalid_elements++;
- Error(ERR_DEBUG, "invalid element %d at position %d, %d",
+ Debug("level:native:SP", "invalid element %d at position %d, %d",
element_old, x, y);
}
}
if (num_invalid_elements > 0)
- Error(ERR_WARN, "found %d invalid elements%s", num_invalid_elements,
- (!options.debug ? " (use '--debug' for more details)" : ""));
+ Warn("found %d invalid elements%s", num_invalid_elements,
+ (!options.debug ? " (use '--debug' for more details)" : ""));
for (i = 0; i < MAX_PLAYERS; i++)
level->initial_player_gravity[i] =
if (port_x < 0 || port_x >= level->fieldx ||
port_y < 0 || port_y >= level->fieldy)
{
- Error(ERR_WARN, "special port position (%d, %d) out of bounds",
- port_x, port_y);
+ Warn("special port position (%d, %d) out of bounds", port_x, port_y);
continue;
}
if (port_element < EL_SP_GRAVITY_PORT_RIGHT ||
port_element > EL_SP_GRAVITY_PORT_UP)
{
- Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y);
+ Warn("no special port at position (%d, %d)", port_x, port_y);
continue;
}
level->time_wheel = 0;
level->amoeba_content = EL_EMPTY;
-#if 1
- // original Supaplex does not use score values -- use default values
-#else
+ // original Supaplex does not use score values -- rate by playing time
for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
level->score[i] = 0;
-#endif
+
+ level->rate_time_over_score = TRUE;
// there are no yamyams in supaplex levels
for (i = 0; i < level->num_yamyam_contents; i++)
if (demo->length + demo_entries >= SP_MAX_TAPE_LEN)
{
- Error(ERR_WARN, "tape truncated: size exceeds maximum SP demo size %d",
- SP_MAX_TAPE_LEN);
+ Warn("tape truncated: size exceeds maximum SP demo size %d",
+ SP_MAX_TAPE_LEN);
break;
}
int demo_repeat = (demo->data[i] & 0xf0) >> 4;
int tape_action = map_key_SP_to_RND(demo_action);
int tape_repeat = demo_repeat + 1;
- byte action[MAX_PLAYERS] = { tape_action, 0, 0, 0 };
+ byte action[MAX_TAPE_ACTIONS] = { tape_action };
boolean success = 0;
int j;
if (!success)
{
- Error(ERR_WARN, "SP demo truncated: size exceeds maximum tape size %d",
- MAX_TAPE_LEN);
+ Warn("SP demo truncated: size exceeds maximum tape size %d",
+ MAX_TAPE_LEN);
break;
}
break;
case 0x13f5:
- element = EL_YAMYAM;
+ element = EL_YAMYAM_UP;
break;
case 0x1425:
break;
case 0x1682: // secret gate (red)
- element = EL_GATE_1_GRAY;
+ element = EL_EM_GATE_1_GRAY;
break;
case 0x1683: // gate (yellow)
break;
case 0x1684: // secret gate (yellow)
- element = EL_GATE_2_GRAY;
+ element = EL_EM_GATE_2_GRAY;
break;
case 0x1685: // gate (blue)
break;
case 0x1686: // secret gate (blue)
- element = EL_GATE_4_GRAY;
+ element = EL_EM_GATE_4_GRAY;
break;
case 0x1687: // gate (green)
break;
case 0x1688: // secret gate (green)
- element = EL_GATE_3_GRAY;
+ element = EL_EM_GATE_3_GRAY;
break;
case 0x1689: // gate (white)
element = EL_INVISIBLE_SAND;
else
{
- Error(ERR_WARN, "unknown Diamond Caves element 0x%04x", element);
+ Warn("unknown Diamond Caves element 0x%04x", element);
+
element = EL_UNKNOWN;
}
break;
{
level->no_valid_file = TRUE;
- Error(ERR_WARN, "cannot decode level from stream -- using empty level");
+ Warn("cannot decode level from stream -- using empty level");
return;
}
level->extra_time = header[56] | (header[57] << 8);
level->shield_normal_time = header[58] | (header[59] << 8);
+ // shield and extra time elements do not have a score
+ level->score[SC_SHIELD] = 0;
+ level->extra_time_score = 0;
+
+ // set time for normal and deadly shields to the same value
+ level->shield_deadly_time = level->shield_normal_time;
+
// Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
// can slip down from flat walls, like normal walls and steel walls
level->em_slippery_gems = TRUE;
+
+ // time score is counted for each 10 seconds left in Diamond Caves levels
+ level->time_score_base = 10;
}
static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
level->no_valid_file = TRUE;
if (!level_info_only)
- Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+ Warn("cannot read level '%s' -- using empty level", filename);
return;
}
{
level->no_valid_file = TRUE;
- Error(ERR_WARN, "unknown DC level file '%s' -- using empty level",
- filename);
+ Warn("unknown DC level file '%s' -- using empty level", filename);
return;
}
{
level->no_valid_file = TRUE;
- Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level",
- filename);
+ Warn("cannot fseek in file '%s' -- using empty level", filename);
return;
}
{
level->no_valid_file = TRUE;
- Error(ERR_WARN, "unknown DC2 level file '%s' -- using empty level",
- filename);
+ Warn("unknown DC2 level file '%s' -- using empty level", filename);
return;
}
level->no_valid_file = TRUE;
if (!level_info_only)
- Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+ Warn("cannot read level '%s' -- using empty level", filename);
return;
}
{
level->no_valid_file = TRUE;
- Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+ Warn("cannot read level '%s' -- using empty level", filename);
return;
}
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;
+ level->time_score_base = 10;
}
if (leveldir_current->latest_engine)
// only Sokoban fields (but not objects) had to be solved before 4.1.1.1
if (level->game_version < VERSION_IDENT(4,1,1,1))
level->sb_objects_needed = FALSE;
+
+ // CE actions were triggered by unfinished digging/collecting up to 4.2.2.0
+ if (level->game_version <= VERSION_IDENT(4,2,2,0))
+ level->finish_dig_collect = FALSE;
}
static void LoadLevel_InitStandardElements(struct LevelInfo *level)
element_info[element].ignition_delay = 8;
}
}
+
+ // set mouse click change events to work for left/middle/right mouse button
+ if (level->game_version < VERSION_IDENT(4,2,3,0))
+ {
+ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ int element = EL_CUSTOM_START + i;
+ struct ElementInfo *ei = &element_info[element];
+
+ for (j = 0; j < ei->num_change_pages; j++)
+ {
+ struct ElementChangeInfo *change = &ei->change_page[j];
+
+ if (change->has_event[CE_CLICKED_BY_MOUSE] ||
+ change->has_event[CE_PRESSED_BY_MOUSE] ||
+ change->has_event[CE_MOUSE_CLICKED_ON_X] ||
+ change->has_event[CE_MOUSE_PRESSED_ON_X])
+ change->trigger_side = CH_SIDE_ANY;
+ }
+ }
+ }
}
static void LoadLevel_InitElements(struct LevelInfo *level)
// copy elements to runtime playfield array
for (x = 0; x < MAX_LEV_FIELDX; x++)
for (y = 0; y < MAX_LEV_FIELDY; y++)
- Feld[x][y] = level->field[x][y];
+ Tile[x][y] = level->field[x][y];
// initialize level size variables for faster access
lev_fieldx = level->fieldx;
{
if (!fileExists(getGlobalLevelTemplateFilename()))
{
- Error(ERR_WARN, "no level template found for this level");
+ Warn("no level template found for this level");
return;
}
int chunk_size = 0;
int x, y;
- for (y = 0; y < level->fieldy; y++)
- for (x = 0; x < level->fieldx; x++)
+ for (y = 0; y < level->fieldy; y++)
+ for (x = 0; x < level->fieldx; x++)
if (level->encoding_16bit_field)
chunk_size += putFile16BitBE(file, level->field[x][y]);
else
// chunk header already written -- write empty chunk data
WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
- Error(ERR_WARN, "cannot save content for element '%d'", element);
+ Warn("cannot save content for element '%d'", element);
+
return;
}
}
if (check != num_changed_custom_elements) // should not happen
- Error(ERR_WARN, "inconsistent number of custom element properties");
+ Warn("inconsistent number of custom element properties");
}
#endif
}
if (check != num_changed_custom_elements) // should not happen
- Error(ERR_WARN, "inconsistent number of custom target elements");
+ Warn("inconsistent number of custom target elements");
}
#endif
}
if (check != num_changed_custom_elements) // should not happen
- Error(ERR_WARN, "inconsistent number of custom element properties");
+ Warn("inconsistent number of custom element properties");
}
#endif
if (!(file = fopen(filename, MODE_WRITE)))
{
- Error(ERR_WARN, "cannot save level file '%s'", filename);
+ Warn("cannot save level file '%s'", filename);
+
return;
}
{
if (level->no_level_file || level->no_valid_file)
{
- Error(ERR_WARN, "cannot dump -- no valid level file found");
+ Warn("cannot dump -- no valid level file found");
return;
}
// at least one (default: the first) player participates in every tape
tape.num_participating_players = 1;
+ tape.property_bits = TAPE_PROPERTY_NONE;
+
tape.level_nr = level_nr;
tape.counter = 0;
tape.changed = FALSE;
tape.playing = FALSE;
tape.pausing = FALSE;
+ tape.scr_fieldx = SCR_FIELDX_DEFAULT;
+ tape.scr_fieldy = SCR_FIELDY_DEFAULT;
+
tape.no_valid_file = FALSE;
}
+static int getTapePosSize(struct TapeInfo *tape)
+{
+ int tape_pos_size = 0;
+
+ if (tape->use_key_actions)
+ tape_pos_size += tape->num_participating_players;
+
+ if (tape->use_mouse_actions)
+ tape_pos_size += 3; // x and y position and mouse button mask
+
+ tape_pos_size += 1; // tape action delay value
+
+ return tape_pos_size;
+}
+
+static void setTapeActionFlags(struct TapeInfo *tape, int value)
+{
+ tape->use_key_actions = FALSE;
+ tape->use_mouse_actions = FALSE;
+
+ if (value != TAPE_USE_MOUSE_ACTIONS_ONLY)
+ tape->use_key_actions = TRUE;
+
+ if (value != TAPE_USE_KEY_ACTIONS_ONLY)
+ tape->use_mouse_actions = TRUE;
+}
+
+static int getTapeActionValue(struct TapeInfo *tape)
+{
+ return (tape->use_key_actions &&
+ tape->use_mouse_actions ? TAPE_USE_KEY_AND_MOUSE_ACTIONS :
+ tape->use_key_actions ? TAPE_USE_KEY_ACTIONS_ONLY :
+ tape->use_mouse_actions ? TAPE_USE_MOUSE_ACTIONS_ONLY :
+ TAPE_ACTIONS_DEFAULT);
+}
+
static int LoadTape_VERS(File *file, int chunk_size, struct TapeInfo *tape)
{
tape->file_version = getFileVersion(file);
}
}
- tape->use_mouse = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+ setTapeActionFlags(tape, getFile8Bit(file));
+
+ tape->property_bits = getFile8Bit(file);
ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
return chunk_size;
}
+static int LoadTape_SCRN(File *file, int chunk_size, struct TapeInfo *tape)
+{
+ tape->scr_fieldx = getFile8Bit(file);
+ tape->scr_fieldy = getFile8Bit(file);
+
+ return chunk_size;
+}
+
static int LoadTape_INFO(File *file, int chunk_size, struct TapeInfo *tape)
{
+ char *level_identifier = NULL;
int level_identifier_size;
int i;
level_identifier_size = getFile16BitBE(file);
- tape->level_identifier =
- checked_realloc(tape->level_identifier, level_identifier_size);
+ level_identifier = checked_malloc(level_identifier_size);
for (i = 0; i < level_identifier_size; i++)
- tape->level_identifier[i] = getFile8Bit(file);
+ level_identifier[i] = getFile8Bit(file);
+
+ strncpy(tape->level_identifier, level_identifier, MAX_FILENAME_LEN);
+ tape->level_identifier[MAX_FILENAME_LEN] = '\0';
+
+ checked_free(level_identifier);
tape->level_nr = getFile16BitBE(file);
static int LoadTape_BODY(File *file, int chunk_size, struct TapeInfo *tape)
{
int i, j;
- int tape_pos_size =
- (tape->use_mouse ? 3 : tape->num_participating_players) + 1;
+ int tape_pos_size = getTapePosSize(tape);
int chunk_size_expected = tape_pos_size * tape->length;
if (chunk_size_expected != chunk_size)
{
if (i >= MAX_TAPE_LEN)
{
- Error(ERR_WARN, "tape truncated -- size exceeds maximum tape size %d",
+ Warn("tape truncated -- size exceeds maximum tape size %d",
MAX_TAPE_LEN);
// tape too large; read and ignore remaining tape data from this chunk
for (;i < tape->length; i++)
- ReadUnusedBytesFromFile(file, tape->num_participating_players + 1);
+ ReadUnusedBytesFromFile(file, tape_pos_size);
break;
}
- if (tape->use_mouse)
- {
- tape->pos[i].action[TAPE_ACTION_LX] = getFile8Bit(file);
- tape->pos[i].action[TAPE_ACTION_LY] = getFile8Bit(file);
- tape->pos[i].action[TAPE_ACTION_BUTTON] = getFile8Bit(file);
-
- tape->pos[i].action[TAPE_ACTION_UNUSED] = 0;
- }
- else
+ if (tape->use_key_actions)
{
for (j = 0; j < MAX_PLAYERS; j++)
{
}
}
+ if (tape->use_mouse_actions)
+ {
+ tape->pos[i].action[TAPE_ACTION_LX] = getFile8Bit(file);
+ tape->pos[i].action[TAPE_ACTION_LY] = getFile8Bit(file);
+ tape->pos[i].action[TAPE_ACTION_BUTTON] = getFile8Bit(file);
+ }
+
tape->pos[i].delay = getFile8Bit(file);
if (tape->file_version == FILE_VERSION_1_0)
default:
tape.no_valid_file = TRUE;
- Error(ERR_WARN, "unsupported Sokoban solution file '%s' ['%d']", filename, c);
+ Warn("unsupported Sokoban solution file '%s' ['%d']", filename, c);
break;
}
{
tape.no_valid_file = TRUE;
- Error(ERR_WARN, "unknown format of tape file '%s'", filename);
+ Warn("unknown format of tape file '%s'", filename);
closeFile(file);
{
tape.no_valid_file = TRUE;
- Error(ERR_WARN, "unknown format of tape file '%s'", filename);
+ Warn("unknown format of tape file '%s'", filename);
closeFile(file);
{
tape.no_valid_file = TRUE;
- Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
+ Warn("unsupported version of tape file '%s'", filename);
closeFile(file);
{
{ "VERS", TAPE_CHUNK_VERS_SIZE, LoadTape_VERS },
{ "HEAD", TAPE_CHUNK_HEAD_SIZE, LoadTape_HEAD },
+ { "SCRN", TAPE_CHUNK_SCRN_SIZE, LoadTape_SCRN },
{ "INFO", -1, LoadTape_INFO },
{ "BODY", -1, LoadTape_BODY },
{ NULL, 0, NULL }
if (chunk_info[i].name == NULL)
{
- Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
+ Warn("unknown chunk '%s' in tape file '%s'",
chunk_name, filename);
+
ReadUnusedBytesFromFile(file, chunk_size);
}
else if (chunk_info[i].size != -1 &&
chunk_info[i].size != chunk_size)
{
- Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
+ Warn("wrong size (%d) of chunk '%s' in tape file '%s'",
chunk_size, chunk_name, filename);
+
ReadUnusedBytesFromFile(file, chunk_size);
}
else
// information, so check them here
if (chunk_size_expected != chunk_size)
{
- Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
+ Warn("wrong size (%d) of chunk '%s' in tape file '%s'",
chunk_size, chunk_name, filename);
}
}
tape.length_seconds = GetTapeLengthSeconds();
#if 0
- printf("::: tape file version: %d\n", tape.file_version);
- printf("::: tape game version: %d\n", tape.game_version);
- printf("::: tape engine version: %d\n", tape.engine_version);
+ Debug("files:LoadTapeFromFilename", "tape file version: %d",
+ tape.file_version);
+ Debug("files:LoadTapeFromFilename", "tape game version: %d",
+ tape.game_version);
+ Debug("files:LoadTapeFromFilename", "tape engine version: %d",
+ tape.engine_version);
#endif
}
CopyNativeTape_SP_to_RND(&level);
}
+static boolean checkSaveTape_SCRN(struct TapeInfo *tape)
+{
+ // chunk required for team mode tapes with non-default screen size
+ return (tape->num_participating_players > 1 &&
+ (tape->scr_fieldx != SCR_FIELDX_DEFAULT ||
+ tape->scr_fieldy != SCR_FIELDY_DEFAULT));
+}
+
static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
{
putFileVersion(file, tape->file_version);
putFile8Bit(file, store_participating_players);
- putFile8Bit(file, (tape->use_mouse ? 1 : 0));
+ putFile8Bit(file, getTapeActionValue(tape));
+
+ putFile8Bit(file, tape->property_bits);
// unused bytes not at the end here for 4-byte alignment of engine_version
WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
putFileVersion(file, tape->engine_version);
}
+static void SaveTape_SCRN(FILE *file, struct TapeInfo *tape)
+{
+ putFile8Bit(file, tape->scr_fieldx);
+ putFile8Bit(file, tape->scr_fieldy);
+}
+
static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
{
int level_identifier_size = strlen(tape->level_identifier) + 1;
for (i = 0; i < tape->length; i++)
{
- if (tape->use_mouse)
- {
- putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_LX]);
- putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_LY]);
- putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_BUTTON]);
- }
- else
+ if (tape->use_key_actions)
{
for (j = 0; j < MAX_PLAYERS; j++)
if (tape->player_participates[j])
putFile8Bit(file, tape->pos[i].action[j]);
}
+ if (tape->use_mouse_actions)
+ {
+ putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_LX]);
+ putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_LY]);
+ putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_BUTTON]);
+ }
+
putFile8Bit(file, tape->pos[i].delay);
}
}
-void SaveTape(int nr)
+void SaveTapeToFilename(char *filename)
{
- char *filename = getTapeFilename(nr);
FILE *file;
- int num_participating_players = 0;
int tape_pos_size;
int info_chunk_size;
int body_chunk_size;
- int i;
-
- InitTapeDirectory(leveldir_current->subdir);
if (!(file = fopen(filename, MODE_WRITE)))
{
- Error(ERR_WARN, "cannot save level recording file '%s'", filename);
+ Warn("cannot save level recording file '%s'", filename);
+
return;
}
- tape.file_version = FILE_VERSION_ACTUAL;
- tape.game_version = GAME_VERSION_ACTUAL;
-
- // count number of participating players
- for (i = 0; i < MAX_PLAYERS; i++)
- if (tape.player_participates[i])
- num_participating_players++;
-
- tape_pos_size = (tape.use_mouse ? 3 : num_participating_players) + 1;
+ tape_pos_size = getTapePosSize(&tape);
info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
body_chunk_size = tape_pos_size * tape.length;
putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE);
SaveTape_HEAD(file, &tape);
+ if (checkSaveTape_SCRN(&tape))
+ {
+ putFileChunkBE(file, "SCRN", TAPE_CHUNK_SCRN_SIZE);
+ SaveTape_SCRN(file, &tape);
+ }
+
putFileChunkBE(file, "INFO", info_chunk_size);
SaveTape_INFO(file, &tape);
fclose(file);
SetFilePermissions(filename, PERMS_PRIVATE);
+}
+
+static void SaveTapeExt(char *filename)
+{
+ int i;
+
+ tape.file_version = FILE_VERSION_ACTUAL;
+ tape.game_version = GAME_VERSION_ACTUAL;
+
+ tape.num_participating_players = 0;
+
+ // count number of participating players
+ for (i = 0; i < MAX_PLAYERS; i++)
+ if (tape.player_participates[i])
+ tape.num_participating_players++;
+
+ SaveTapeToFilename(filename);
tape.changed = FALSE;
}
+void SaveTape(int nr)
+{
+ char *filename = getTapeFilename(nr);
+
+ InitTapeDirectory(leveldir_current->subdir);
+
+ SaveTapeExt(filename);
+}
+
+void SaveScoreTape(int nr)
+{
+ char *filename = getScoreTapeFilename(tape.score_tape_basename, nr);
+
+ // used instead of "leveldir_current->subdir" (for network games)
+ InitScoreTapeDirectory(levelset.identifier, nr);
+
+ SaveTapeExt(filename);
+}
+
static boolean SaveTapeCheckedExt(int nr, char *msg_replace, char *msg_saved,
unsigned int req_state_added)
{
if (tape->no_valid_file)
{
- Error(ERR_WARN, "cannot dump -- no valid tape file found");
+ Warn("cannot dump -- no valid tape file found");
return;
}
// score file functions
// ============================================================================
-void LoadScore(int nr)
+static void setScoreInfoToDefaults(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+ {
+ strcpy(scores.entry[i].tape_basename, UNDEFINED_FILENAME);
+ strcpy(scores.entry[i].name, EMPTY_PLAYER_NAME);
+ scores.entry[i].score = 0;
+ scores.entry[i].time = 0;
+ }
+}
+
+static void LoadScore_OLD(int nr)
{
int i;
char *filename = getScoreFilename(nr);
char *line_ptr;
FILE *file;
- // always start with reliable default values
- for (i = 0; i < MAX_SCORE_ENTRIES; i++)
- {
- strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
- highscore[i].Score = 0;
- }
-
if (!(file = fopen(filename, MODE_READ)))
return;
if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
cookie[strlen(cookie) - 1] = '\0';
- if (!checkCookieString(cookie, SCORE_COOKIE))
+ if (!checkCookieString(cookie, SCORE_COOKIE_TMPL))
{
- Error(ERR_WARN, "unknown format of score file '%s'", filename);
+ Warn("unknown format of score file '%s'", filename);
+
fclose(file);
+
return;
}
for (i = 0; i < MAX_SCORE_ENTRIES; i++)
{
- if (fscanf(file, "%d", &highscore[i].Score) == EOF)
- Error(ERR_WARN, "fscanf() failed; %s", strerror(errno));
+ if (fscanf(file, "%d", &scores.entry[i].score) == EOF)
+ Warn("fscanf() failed; %s", strerror(errno));
+
if (fgets(line, MAX_LINE_LEN, file) == NULL)
line[0] = '\0';
{
if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
{
- strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
- highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
+ strncpy(scores.entry[i].name, line_ptr, MAX_PLAYER_NAME_LEN);
+ scores.entry[i].name[MAX_PLAYER_NAME_LEN] = '\0';
break;
}
}
fclose(file);
}
-void SaveScore(int nr)
+static void ConvertScore_OLD(void)
+{
+ // only convert score to time for levels that rate playing time over score
+ if (!level.rate_time_over_score)
+ return;
+
+ // convert old score to playing time for score-less levels (like Supaplex)
+ int time_final_max = 999;
+ int i;
+
+ for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+ {
+ int score = scores.entry[i].score;
+
+ if (score > 0 && score < time_final_max)
+ scores.entry[i].time = (time_final_max - score - 1) * FRAMES_PER_SECOND;
+ }
+}
+
+static int LoadScore_VERS(File *file, int chunk_size, struct ScoreInfo *scores)
+{
+ scores->file_version = getFileVersion(file);
+ scores->game_version = getFileVersion(file);
+
+ return chunk_size;
+}
+
+static int LoadScore_INFO(File *file, int chunk_size, struct ScoreInfo *scores)
{
+ char *level_identifier = NULL;
+ int level_identifier_size;
int i;
- int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE);
- char *filename = getScoreFilename(nr);
- FILE *file;
- // used instead of "leveldir_current->subdir" (for network games)
- InitScoreDirectory(levelset.identifier);
+ level_identifier_size = getFile16BitBE(file);
- if (!(file = fopen(filename, MODE_WRITE)))
+ level_identifier = checked_malloc(level_identifier_size);
+
+ for (i = 0; i < level_identifier_size; i++)
+ level_identifier[i] = getFile8Bit(file);
+
+ strncpy(scores->level_identifier, level_identifier, MAX_FILENAME_LEN);
+ scores->level_identifier[MAX_FILENAME_LEN] = '\0';
+
+ checked_free(level_identifier);
+
+ scores->level_nr = getFile16BitBE(file);
+ scores->num_entries = getFile16BitBE(file);
+
+ chunk_size = 2 + level_identifier_size + 2 + 2;
+
+ return chunk_size;
+}
+
+static int LoadScore_NAME(File *file, int chunk_size, struct ScoreInfo *scores)
+{
+ int i, j;
+
+ for (i = 0; i < scores->num_entries; i++)
{
- Error(ERR_WARN, "cannot save score for level %d", nr);
- return;
+ for (j = 0; j < MAX_PLAYER_NAME_LEN; j++)
+ scores->entry[i].name[j] = getFile8Bit(file);
+
+ scores->entry[i].name[MAX_PLAYER_NAME_LEN] = '\0';
}
- fprintf(file, "%s\n\n", SCORE_COOKIE);
+ chunk_size = scores->num_entries * MAX_PLAYER_NAME_LEN;
- for (i = 0; i < MAX_SCORE_ENTRIES; i++)
- fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
+ return chunk_size;
+}
- fclose(file);
+static int LoadScore_SCOR(File *file, int chunk_size, struct ScoreInfo *scores)
+{
+ int i;
- SetFilePermissions(filename, permissions);
+ for (i = 0; i < scores->num_entries; i++)
+ scores->entry[i].score = getFile16BitBE(file);
+
+ chunk_size = scores->num_entries * 2;
+
+ return chunk_size;
}
+static int LoadScore_TIME(File *file, int chunk_size, struct ScoreInfo *scores)
+{
+ int i;
-// ============================================================================
-// setup file functions
-// ============================================================================
+ for (i = 0; i < scores->num_entries; i++)
+ scores->entry[i].time = getFile32BitBE(file);
-#define TOKEN_STR_PLAYER_PREFIX "player_"
+ chunk_size = scores->num_entries * 4;
+ return chunk_size;
+}
-static struct TokenInfo global_setup_tokens[] =
+static int LoadScore_TAPE(File *file, int chunk_size, struct ScoreInfo *scores)
{
+ int i, j;
+
+ for (i = 0; i < scores->num_entries; i++)
+ {
+ for (j = 0; j < MAX_SCORE_TAPE_BASENAME_LEN; j++)
+ scores->entry[i].tape_basename[j] = getFile8Bit(file);
+
+ scores->entry[i].tape_basename[MAX_SCORE_TAPE_BASENAME_LEN] = '\0';
+ }
+
+ chunk_size = scores->num_entries * MAX_SCORE_TAPE_BASENAME_LEN;
+
+ return chunk_size;
+}
+
+void LoadScore(int nr)
+{
+ char *filename = getScoreFilename(nr);
+ char cookie[MAX_LINE_LEN];
+ char chunk_name[CHUNK_ID_LEN + 1];
+ int chunk_size;
+ boolean old_score_file_format = FALSE;
+ File *file;
+
+ // always start with reliable default values
+ setScoreInfoToDefaults();
+
+ if (!(file = openFile(filename, MODE_READ)))
+ return;
+
+ getFileChunkBE(file, chunk_name, NULL);
+ if (strEqual(chunk_name, "RND1"))
+ {
+ getFile32BitBE(file); // not used
+
+ getFileChunkBE(file, chunk_name, NULL);
+ if (!strEqual(chunk_name, "SCOR"))
+ {
+ Warn("unknown format of score file '%s'", filename);
+
+ closeFile(file);
+
+ return;
+ }
+ }
+ else // check for old file format with cookie string
+ {
+ strcpy(cookie, chunk_name);
+ if (getStringFromFile(file, &cookie[4], MAX_LINE_LEN - 4) == NULL)
+ cookie[4] = '\0';
+ if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
+ cookie[strlen(cookie) - 1] = '\0';
+
+ if (!checkCookieString(cookie, SCORE_COOKIE_TMPL))
+ {
+ Warn("unknown format of score file '%s'", filename);
+
+ closeFile(file);
+
+ return;
+ }
+
+ old_score_file_format = TRUE;
+ }
+
+ if (old_score_file_format)
+ {
+ // score files from versions before 4.2.4.0 without chunk structure
+ LoadScore_OLD(nr);
+
+ // convert score to time, if possible (mainly for Supaplex levels)
+ ConvertScore_OLD();
+ }
+ else
+ {
+ static struct
+ {
+ char *name;
+ int size;
+ int (*loader)(File *, int, struct ScoreInfo *);
+ }
+ chunk_info[] =
+ {
+ { "VERS", SCORE_CHUNK_VERS_SIZE, LoadScore_VERS },
+ { "INFO", -1, LoadScore_INFO },
+ { "NAME", -1, LoadScore_NAME },
+ { "SCOR", -1, LoadScore_SCOR },
+ { "TIME", -1, LoadScore_TIME },
+ { "TAPE", -1, LoadScore_TAPE },
+
+ { NULL, 0, NULL }
+ };
+
+ while (getFileChunkBE(file, chunk_name, &chunk_size))
+ {
+ int i = 0;
+
+ while (chunk_info[i].name != NULL &&
+ !strEqual(chunk_name, chunk_info[i].name))
+ i++;
+
+ if (chunk_info[i].name == NULL)
+ {
+ Warn("unknown chunk '%s' in score file '%s'",
+ chunk_name, filename);
+
+ ReadUnusedBytesFromFile(file, chunk_size);
+ }
+ else if (chunk_info[i].size != -1 &&
+ chunk_info[i].size != chunk_size)
+ {
+ Warn("wrong size (%d) of chunk '%s' in score file '%s'",
+ chunk_size, chunk_name, filename);
+
+ ReadUnusedBytesFromFile(file, chunk_size);
+ }
+ else
+ {
+ // call function to load this score chunk
+ int chunk_size_expected =
+ (chunk_info[i].loader)(file, chunk_size, &scores);
+
+ // the size of some chunks cannot be checked before reading other
+ // chunks first (like "HEAD" and "BODY") that contain some header
+ // information, so check them here
+ if (chunk_size_expected != chunk_size)
+ {
+ Warn("wrong size (%d) of chunk '%s' in score file '%s'",
+ chunk_size, chunk_name, filename);
+ }
+ }
+ }
+ }
+
+ closeFile(file);
+}
+
+#if ENABLE_HISTORIC_CHUNKS
+void SaveScore_OLD(int nr)
+{
+ int i;
+ int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE);
+ char *filename = getScoreFilename(nr);
+ FILE *file;
+
+ // used instead of "leveldir_current->subdir" (for network games)
+ InitScoreDirectory(levelset.identifier);
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot save score for level %d", nr);
+
+ return;
+ }
+
+ fprintf(file, "%s\n\n", SCORE_COOKIE);
+
+ for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+ fprintf(file, "%d %s\n", scores.entry[i].score, scores.entry[i].name);
+
+ fclose(file);
+
+ SetFilePermissions(filename, permissions);
+}
+#endif
+
+static void SaveScore_VERS(FILE *file, struct ScoreInfo *scores)
+{
+ putFileVersion(file, scores->file_version);
+ putFileVersion(file, scores->game_version);
+}
+
+static void SaveScore_INFO(FILE *file, struct ScoreInfo *scores)
+{
+ int level_identifier_size = strlen(scores->level_identifier) + 1;
+ int i;
+
+ putFile16BitBE(file, level_identifier_size);
+
+ for (i = 0; i < level_identifier_size; i++)
+ putFile8Bit(file, scores->level_identifier[i]);
+
+ putFile16BitBE(file, scores->level_nr);
+ putFile16BitBE(file, scores->num_entries);
+}
+
+static void SaveScore_NAME(FILE *file, struct ScoreInfo *scores)
+{
+ int i, j;
+
+ for (i = 0; i < scores->num_entries; i++)
+ {
+ int name_size = strlen(scores->entry[i].name);
+
+ for (j = 0; j < MAX_PLAYER_NAME_LEN; j++)
+ putFile8Bit(file, (j < name_size ? scores->entry[i].name[j] : 0));
+ }
+}
+
+static void SaveScore_SCOR(FILE *file, struct ScoreInfo *scores)
+{
+ int i;
+
+ for (i = 0; i < scores->num_entries; i++)
+ putFile16BitBE(file, scores->entry[i].score);
+}
+
+static void SaveScore_TIME(FILE *file, struct ScoreInfo *scores)
+{
+ int i;
+
+ for (i = 0; i < scores->num_entries; i++)
+ putFile32BitBE(file, scores->entry[i].time);
+}
+
+static void SaveScore_TAPE(FILE *file, struct ScoreInfo *scores)
+{
+ int i, j;
+
+ for (i = 0; i < scores->num_entries; i++)
+ {
+ int size = strlen(scores->entry[i].tape_basename);
+
+ for (j = 0; j < MAX_SCORE_TAPE_BASENAME_LEN; j++)
+ putFile8Bit(file, (j < size ? scores->entry[i].tape_basename[j] : 0));
+ }
+}
+
+static void SaveScoreToFilename(char *filename)
+{
+ FILE *file;
+ int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE);
+ int info_chunk_size;
+ int name_chunk_size;
+ int scor_chunk_size;
+ int time_chunk_size;
+ int tape_chunk_size;
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot save score file '%s'", filename);
+
+ return;
+ }
+
+ info_chunk_size = 2 + (strlen(scores.level_identifier) + 1) + 2 + 2;
+ name_chunk_size = scores.num_entries * MAX_PLAYER_NAME_LEN;
+ scor_chunk_size = scores.num_entries * 2;
+ time_chunk_size = scores.num_entries * 4;
+ tape_chunk_size = scores.num_entries * MAX_SCORE_TAPE_BASENAME_LEN;
+
+ putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
+ putFileChunkBE(file, "SCOR", CHUNK_SIZE_NONE);
+
+ putFileChunkBE(file, "VERS", SCORE_CHUNK_VERS_SIZE);
+ SaveScore_VERS(file, &scores);
+
+ putFileChunkBE(file, "INFO", info_chunk_size);
+ SaveScore_INFO(file, &scores);
+
+ putFileChunkBE(file, "NAME", name_chunk_size);
+ SaveScore_NAME(file, &scores);
+
+ putFileChunkBE(file, "SCOR", scor_chunk_size);
+ SaveScore_SCOR(file, &scores);
+
+ putFileChunkBE(file, "TIME", time_chunk_size);
+ SaveScore_TIME(file, &scores);
+
+ putFileChunkBE(file, "TAPE", tape_chunk_size);
+ SaveScore_TAPE(file, &scores);
+
+ fclose(file);
+
+ SetFilePermissions(filename, permissions);
+}
+
+void SaveScore(int nr)
+{
+ char *filename = getScoreFilename(nr);
+ int i;
+
+ // used instead of "leveldir_current->subdir" (for network games)
+ InitScoreDirectory(levelset.identifier);
+
+ scores.file_version = FILE_VERSION_ACTUAL;
+ scores.game_version = GAME_VERSION_ACTUAL;
+
+ strncpy(scores.level_identifier, levelset.identifier, MAX_FILENAME_LEN);
+ scores.level_identifier[MAX_FILENAME_LEN] = '\0';
+ scores.level_nr = level_nr;
+
+ for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+ if (scores.entry[i].score == 0 &&
+ scores.entry[i].time == 0 &&
+ strEqual(scores.entry[i].name, EMPTY_PLAYER_NAME))
+ break;
+
+ scores.num_entries = i;
+
+ if (scores.num_entries == 0)
+ return;
+
+ SaveScoreToFilename(filename);
+}
+
+
+// ============================================================================
+// setup file functions
+// ============================================================================
+
+#define TOKEN_STR_PLAYER_PREFIX "player_"
+
+
+static struct TokenInfo global_setup_tokens[] =
+{
+ {
+ TYPE_STRING,
+ &setup.player_name, "player_name"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.multiple_users, "multiple_users"
+ },
{
- TYPE_STRING,
- &setup.player_name, "player_name"
- },
- {
TYPE_SWITCH,
&setup.sound, "sound"
},
TYPE_SWITCH,
&setup.scroll_delay, "scroll_delay"
},
+ {
+ TYPE_SWITCH,
+ &setup.forced_scroll_delay, "forced_scroll_delay"
+ },
{
TYPE_INTEGER,
&setup.scroll_delay_value, "scroll_delay_value"
},
{
TYPE_SWITCH,
- &setup.skip_scores_after_game, "skip_scores_after_game"
+ &setup.count_score_after_game, "count_score_after_game"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.show_scores_after_game, "show_scores_after_game"
},
{
TYPE_SWITCH,
TYPE_SWITCH,
&setup.ask_on_game_over, "ask_on_game_over"
},
+ {
+ TYPE_SWITCH,
+ &setup.ask_on_quit_game, "ask_on_quit_game"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.ask_on_quit_program, "ask_on_quit_program"
+ },
{
TYPE_SWITCH,
&setup.quick_switch, "quick_player_switch"
TYPE_SWITCH,
&setup.prefer_aga_graphics, "prefer_aga_graphics"
},
+ {
+ TYPE_SWITCH,
+ &setup.prefer_lowpass_sounds, "prefer_lowpass_sounds"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.prefer_extra_panel_items, "prefer_extra_panel_items"
+ },
{
TYPE_SWITCH,
&setup.game_speed_extended, "game_speed_extended"
TYPE_SWITCH,
&setup.editor.show_element_token, "editor.show_element_token"
},
+ {
+ TYPE_SWITCH,
+ &setup.editor.show_read_only_warning, "editor.show_read_only_warning"
+ },
};
static struct TokenInfo editor_cascade_setup_tokens[] =
static struct TokenInfo system_setup_tokens[] =
{
+ {
+ TYPE_STRING,
+ &setup.system.sdl_renderdriver, "system.sdl_renderdriver"
+ },
{
TYPE_STRING,
&setup.system.sdl_videodriver, "system.sdl_videodriver"
TYPE_BOOLEAN,
&setup.internal.show_scaling_in_title, "show_scaling_in_title"
},
+ {
+ TYPE_BOOLEAN,
+ &setup.internal.create_user_levelset, "create_user_levelset"
+ },
{
TYPE_BOOLEAN,
&setup.internal.menu_game, "menu_game"
TYPE_BOOLEAN,
&setup.debug.show_frames_per_second, "debug.show_frames_per_second"
},
+ {
+ TYPE_SWITCH3,
+ &setup.debug.xsn_mode, "debug.xsn_mode"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.debug.xsn_percent, "debug.xsn_percent"
+ },
};
static struct TokenInfo options_setup_tokens[] =
},
};
-static char *get_corrected_login_name(char *login_name)
-{
- // needed because player name must be a fixed length string
- char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
-
- strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
- login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
-
- if (strlen(login_name) > MAX_PLAYER_NAME_LEN) // name has been cut
- if (strchr(login_name_new, ' '))
- *strchr(login_name_new, ' ') = '\0';
-
- return login_name_new;
-}
-
static void setSetupInfoToDefaults(struct SetupInfo *si)
{
int i;
- si->player_name = get_corrected_login_name(getLoginName());
+ si->player_name = getStringCopy(getDefaultUserName(user.nr));
+
+ si->multiple_users = TRUE;
si->sound = TRUE;
si->sound_loops = TRUE;
si->sound_simple = TRUE;
si->toons = TRUE;
si->scroll_delay = TRUE;
+ si->forced_scroll_delay = FALSE;
si->scroll_delay_value = STD_SCROLL_DELAY;
si->engine_snapshot_mode = getStringCopy(STR_SNAPSHOT_MODE_DEFAULT);
si->engine_snapshot_memory = SNAPSHOT_MEMORY_DEFAULT;
si->skip_levels = TRUE;
si->increment_levels = TRUE;
si->auto_play_next_level = TRUE;
- si->skip_scores_after_game = FALSE;
+ si->count_score_after_game = TRUE;
+ si->show_scores_after_game = TRUE;
si->time_limit = TRUE;
si->fullscreen = FALSE;
si->window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
si->ask_on_escape = TRUE;
si->ask_on_escape_editor = TRUE;
si->ask_on_game_over = TRUE;
+ si->ask_on_quit_game = TRUE;
+ si->ask_on_quit_program = TRUE;
si->quick_switch = FALSE;
si->input_on_focus = FALSE;
si->prefer_aga_graphics = TRUE;
+ si->prefer_lowpass_sounds = FALSE;
+ si->prefer_extra_panel_items = TRUE;
si->game_speed_extended = FALSE;
si->game_frame_delay = GAME_FRAME_DELAY;
si->sp_show_border_elements = FALSE;
si->editor.show_element_token = FALSE;
+ si->editor.show_read_only_warning = TRUE;
+
si->editor.use_template_for_new_levels = TRUE;
si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
si->input[i].key.drop = (i == 0 ? DEFAULT_KEY_DROP : KSYM_UNDEFINED);
}
+ si->system.sdl_renderdriver = getStringCopy(ARG_DEFAULT);
si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT);
si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
si->internal.default_level_series = getStringCopy(UNDEFINED_LEVELSET);
si->internal.choose_from_top_leveldir = FALSE;
si->internal.show_scaling_in_title = TRUE;
+ si->internal.create_user_levelset = TRUE;
si->internal.default_window_width = WIN_XSIZE_DEFAULT;
si->internal.default_window_height = WIN_YSIZE_DEFAULT;
si->debug.show_frames_per_second = FALSE;
+ si->debug.xsn_mode = AUTO;
+ si->debug.xsn_percent = 0;
+
si->options.verbose = FALSE;
#if defined(PLATFORM_ANDROID)
si->fullscreen = TRUE;
#endif
+
+ setHideSetupEntry(&setup.debug.xsn_mode);
}
static void setSetupInfoToDefaults_AutoSetup(struct SetupInfo *si)
{
char *hide_setup_token = getHideSetupToken(setup_value);
+ if (hide_setup_hash == NULL)
+ hide_setup_hash = newSetupFileHash();
+
if (setup_value != NULL)
setHashEntry(hide_setup_hash, hide_setup_token, "");
}
+void removeHideSetupEntry(void *setup_value)
+{
+ char *hide_setup_token = getHideSetupToken(setup_value);
+
+ if (setup_value != NULL)
+ removeHashEntry(hide_setup_hash, hide_setup_token);
+}
+
boolean hideSetupEntry(void *setup_value)
{
char *hide_setup_token = getHideSetupToken(setup_value);
// check if this setup option should be hidden in the setup menu
if (token_hide_value != NULL && get_boolean_from_string(token_hide_value))
setHideSetupEntry(token_info[token_nr].value);
+
+ free(token_hide_text);
}
static void setSetupInfoFromTokenInfo(SetupFileHash *setup_file_hash,
if (!setup_file_hash)
return;
- if (hide_setup_hash == NULL)
- hide_setup_hash = newSetupFileHash();
-
for (i = 0; i < ARRAY_SIZE(global_setup_tokens); i++)
setSetupInfoFromTokenInfo(setup_file_hash, global_setup_tokens, i);
editor_cascade_setup_tokens[i].text));
}
+void LoadUserNames(void)
+{
+ int last_user_nr = user.nr;
+ int i;
+
+ if (global.user_names != NULL)
+ {
+ for (i = 0; i < MAX_PLAYER_NAMES; i++)
+ checked_free(global.user_names[i]);
+
+ checked_free(global.user_names);
+ }
+
+ global.user_names = checked_calloc(MAX_PLAYER_NAMES * sizeof(char *));
+
+ for (i = 0; i < MAX_PLAYER_NAMES; i++)
+ {
+ user.nr = i;
+
+ SetupFileHash *setup_file_hash = loadSetupFileHash(getSetupFilename());
+
+ if (setup_file_hash)
+ {
+ char *player_name = getHashEntry(setup_file_hash, "player_name");
+
+ global.user_names[i] = getFixedUserName(player_name);
+
+ freeSetupFileHash(setup_file_hash);
+ }
+
+ if (global.user_names[i] == NULL)
+ global.user_names[i] = getStringCopy(getDefaultUserName(i));
+ }
+
+ user.nr = last_user_nr;
+}
+
void LoadSetupFromFilename(char *filename)
{
SetupFileHash *setup_file_hash = loadSetupFileHash(filename);
}
else
{
- Error(ERR_DEBUG, "using default setup values");
+ Debug("setup", "using default setup values");
}
}
char *player_name_new;
// needed to work around problems with fixed length strings
- player_name_new = get_corrected_login_name(setup.player_name);
+ player_name_new = getFixedUserName(setup.player_name);
free(setup.player_name);
setup.player_name = player_name_new;
if (!(file = fopen(filename, MODE_READ)))
{
- Error(ERR_WARN, "cannot read game controller mappings file '%s'", filename);
+ Warn("cannot read game controller mappings file '%s'", filename);
return;
}
if (!(file = fopen(filename, MODE_WRITE)))
{
- Error(ERR_WARN, "cannot write setup file '%s'", filename);
+ Warn("cannot write setup file '%s'", filename);
+
return;
}
for (i = 0; i < ARRAY_SIZE(global_setup_tokens); i++)
{
// just to make things nicer :)
- if (global_setup_tokens[i].value == &setup.sound ||
+ if (global_setup_tokens[i].value == &setup.multiple_users ||
+ global_setup_tokens[i].value == &setup.sound ||
global_setup_tokens[i].value == &setup.graphics_set ||
global_setup_tokens[i].value == &setup.volume_simple ||
global_setup_tokens[i].value == &setup.network_mode ||
fprintf(file, "\n");
for (i = 0; i < ARRAY_SIZE(debug_setup_tokens); i++)
- fprintf(file, "%s\n", getSetupLine(debug_setup_tokens, "", i));
+ if (!strPrefix(debug_setup_tokens[i].text, "debug.xsn_") ||
+ setup.debug.xsn_mode != AUTO)
+ fprintf(file, "%s\n", getSetupLine(debug_setup_tokens, "", i));
fprintf(file, "\n");
for (i = 0; i < ARRAY_SIZE(options_setup_tokens); i++)
if (!(file = fopen(filename, MODE_WRITE)))
{
- Error(ERR_WARN, "cannot write auto setup file '%s'", filename);
+ Warn("cannot write auto setup file '%s'", filename);
+
free(filename);
+
return;
}
if (!(file = fopen(filename, MODE_WRITE)))
{
- Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
+ Warn("cannot write editor cascade state file '%s'", filename);
+
free(filename);
+
return;
}
if (!(file = fopen(filename, MODE_WRITE)))
{
- Error(ERR_WARN, "cannot write game controller mappings file '%s'",filename);
+ Warn("cannot write game controller mappings file '%s'", filename);
return;
}
if (value != NULL)
return atoi(value);
- Error(ERR_WARN, "unknown element token '%s'", token);
+ Warn("unknown element token '%s'", token);
return EL_UNDEFINED;
}
static int get_anim_action_parameter_value(char *token)
{
+ // check most common default case first to massively speed things up
+ if (strEqual(token, ARG_UNDEFINED))
+ return ANIM_EVENT_ACTION_NONE;
+
int result = getImageIDFromToken(token);
if (result == -1)
{
result = get_anim_parameter_values(value);
}
- else if (strEqual(suffix, ".init_event_action") ||
+ else if (strEqual(suffix, ".init_delay_action") ||
+ strEqual(suffix, ".anim_delay_action") ||
+ strEqual(suffix, ".post_delay_action") ||
+ strEqual(suffix, ".init_event_action") ||
strEqual(suffix, ".anim_event_action"))
{
result = get_anim_action_parameter_value(value_raw);
if (string_has_parameter(value, "reverse"))
result |= STYLE_REVERSE;
+ if (string_has_parameter(value, "leftmost_position"))
+ result |= STYLE_LEFTMOST_POSITION;
+
+ if (string_has_parameter(value, "block_clicks"))
+ result |= STYLE_BLOCK;
+
if (string_has_parameter(value, "passthrough_clicks"))
result |= STYLE_PASSTHROUGH;
string_has_parameter(value, "curtain") ? FADE_MODE_CURTAIN :
FADE_MODE_DEFAULT);
}
+ else if (strEqual(suffix, ".auto_delay_unit"))
+ {
+ result = (string_has_parameter(value, "ms") ? AUTO_DELAY_UNIT_MS :
+ string_has_parameter(value, "frames") ? AUTO_DELAY_UNIT_FRAMES :
+ AUTO_DELAY_UNIT_DEFAULT);
+ }
else if (strPrefix(suffix, ".font")) // (may also be ".font_xyz")
{
result = gfx.get_font_from_token_function(value);
title_initial_first_default.post_delay;
titlescreen_initial_first_default.auto_delay =
title_initial_first_default.auto_delay;
+ titlescreen_initial_first_default.auto_delay_unit =
+ title_initial_first_default.auto_delay_unit;
titlescreen_first_default.fade_mode = title_first_default.fade_mode;
titlescreen_first_default.fade_delay = title_first_default.fade_delay;
titlescreen_first_default.post_delay = title_first_default.post_delay;
titlescreen_first_default.auto_delay = title_first_default.auto_delay;
+ titlescreen_first_default.auto_delay_unit =
+ title_first_default.auto_delay_unit;
titlemessage_initial_first_default.fade_mode =
title_initial_first_default.fade_mode;
titlemessage_initial_first_default.fade_delay =
title_initial_first_default.post_delay;
titlemessage_initial_first_default.auto_delay =
title_initial_first_default.auto_delay;
+ titlemessage_initial_first_default.auto_delay_unit =
+ title_initial_first_default.auto_delay_unit;
titlemessage_first_default.fade_mode = title_first_default.fade_mode;
titlemessage_first_default.fade_delay = title_first_default.fade_delay;
titlemessage_first_default.post_delay = title_first_default.post_delay;
titlemessage_first_default.auto_delay = title_first_default.auto_delay;
+ titlemessage_first_default.auto_delay_unit =
+ title_first_default.auto_delay_unit;
titlescreen_initial_default.fade_mode = title_initial_default.fade_mode;
titlescreen_initial_default.fade_delay = title_initial_default.fade_delay;
titlescreen_initial_default.post_delay = title_initial_default.post_delay;
titlescreen_initial_default.auto_delay = title_initial_default.auto_delay;
+ titlescreen_initial_default.auto_delay_unit =
+ title_initial_default.auto_delay_unit;
titlescreen_default.fade_mode = title_default.fade_mode;
titlescreen_default.fade_delay = title_default.fade_delay;
titlescreen_default.post_delay = title_default.post_delay;
titlescreen_default.auto_delay = title_default.auto_delay;
+ titlescreen_default.auto_delay_unit = title_default.auto_delay_unit;
titlemessage_initial_default.fade_mode = title_initial_default.fade_mode;
titlemessage_initial_default.fade_delay = title_initial_default.fade_delay;
titlemessage_initial_default.post_delay = title_initial_default.post_delay;
- titlemessage_initial_default.auto_delay = title_initial_default.auto_delay;
+ titlemessage_initial_default.auto_delay_unit =
+ title_initial_default.auto_delay_unit;
titlemessage_default.fade_mode = title_default.fade_mode;
titlemessage_default.fade_delay = title_default.fade_delay;
titlemessage_default.post_delay = title_default.post_delay;
titlemessage_default.auto_delay = title_default.auto_delay;
+ titlemessage_default.auto_delay_unit = title_default.auto_delay_unit;
// special case: initialize "ARG_DEFAULT" values in static default config
// (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode")
{ TYPE_INTEGER, &tfi.fade_delay, ".fade_delay" },
{ TYPE_INTEGER, &tfi.post_delay, ".post_delay" },
{ TYPE_INTEGER, &tfi.auto_delay, ".auto_delay" },
+ { TYPE_INTEGER, &tfi.auto_delay_unit, ".auto_delay_unit" },
{ -1, NULL, NULL }
};
{ TYPE_INTEGER, &tmi.fade_delay, ".fade_delay" },
{ TYPE_INTEGER, &tmi.post_delay, ".post_delay" },
{ TYPE_INTEGER, &tmi.auto_delay, ".auto_delay" },
+ { TYPE_INTEGER, &tmi.auto_delay_unit, ".auto_delay_unit" },
{ -1, NULL, NULL }
};
{
if (num_unknown_tokens == 0)
{
- Error(ERR_INFO_LINE, "-");
- Error(ERR_INFO, "warning: unknown token(s) found in config file:");
- Error(ERR_INFO, "- config file: '%s'", filename);
+ Warn("---");
+ Warn("unknown token(s) found in config file:");
+ Warn("- config file: '%s'", filename);
num_unknown_tokens++;
}
- Error(ERR_INFO, "- token: '%s'", list->token);
+ Warn("- token: '%s'", list->token);
}
}
if (num_unknown_tokens > 0)
- Error(ERR_INFO_LINE, "-");
+ Warn("---");
while (*num_elements % 4) // pad with empty elements, if needed
(*elements)[(*num_elements)++] = EL_EMPTY;
#if 0
for (i = 0; i < *num_elements; i++)
- printf("editor: element '%s' [%d]\n",
- element_info[(*elements)[i]].token_name, (*elements)[i]);
+ Debug("editor", "element '%s' [%d]\n",
+ element_info[(*elements)[i]].token_name, (*elements)[i]);
#endif
}
if ((dir = openDirectory(music_directory)) == NULL)
{
- Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
+ Warn("cannot read music directory '%s'", music_directory);
+
return;
}
{
if (token_nr == 0)
{
- Error(ERR_INFO_LINE, "-");
- Error(ERR_INFO, "warning: unknown token(s) found in config file:");
- Error(ERR_INFO, "- config file: '%s'", filename);
+ Warn("---");
+ Warn("unknown token(s) found in config file:");
+ Warn("- config file: '%s'", filename);
}
- Error(ERR_INFO, "- token: '%s'", token);
+ Warn("- token: '%s'", token);
}
static void print_unknown_token_end(int token_nr)
{
if (token_nr > 0)
- Error(ERR_INFO_LINE, "-");
+ Warn("---");
}
void LoadHelpAnimInfo(void)
#if 0
for (i = 0; i < num_list_entries; i++)
- 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,
- helpanim_info[i].delay);
+ Debug("files:LoadHelpAnimInfo", "'%s': %d, %d, %d => %d",
+ EL_NAME(helpanim_info[i].element),
+ helpanim_info[i].element,
+ helpanim_info[i].action,
+ helpanim_info[i].direction,
+ helpanim_info[i].delay);
#endif
}
#if 0
BEGIN_HASH_ITERATION(helptext_info, itr)
{
- printf("::: '%s' => '%s'\n",
- HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
+ Debug("files:LoadHelpTextInfo", "'%s' => '%s'",
+ HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
}
END_HASH_ITERATION(hash, itr)
#endif
global.convert_leveldir);
if (convert_leveldir == NULL)
- Error(ERR_EXIT, "no such level identifier: '%s'",
- global.convert_leveldir);
+ Fail("no such level identifier: '%s'", global.convert_leveldir);
leveldir_current = convert_leveldir;
BlitBitmap(drawto, bitmap1, SX, SY, TILEX, TILEY, 0, 0);
if (SDL_SaveBMP(bitmap1->surface, filename1) != 0)
- Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1);
+ Fail("cannot save level sketch image file '%s'", filename1);
DrawSizedElement(0, 0, element, MINI_TILESIZE);
BlitBitmap(drawto, bitmap2, SX, SY, MINI_TILEX, MINI_TILEY, 0, 0);
if (SDL_SaveBMP(bitmap2->surface, filename2) != 0)
- Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2);
+ Fail("cannot save level sketch image file '%s'", filename2);
free(filename1);
free(filename2);
if (options.debug)
fprintf(stderr, "\n");
- Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS);
+ Info("%d normal and small images created", NUM_FILE_ELEMENTS);
CloseAllAndExit(0);
}
}
if (SDL_SaveBMP(bitmap->surface, dst_filename) != 0)
- Error(ERR_EXIT, "cannot save CE graphics file '%s'", dst_filename);
+ Fail("cannot save CE graphics file '%s'", dst_filename);
FreeBitmap(bitmap);