#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 1 // unused tape header bytes
+#define TAPE_CHUNK_SCRN_SIZE 2 // size of screen size chunk
#define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x))
#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
&li.solved_by_one_player, FALSE
},
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(12),
+ &li.time_score_base, 1
+ },
+
{
-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)
{
&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 (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;
}
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,
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)
tape.playing = FALSE;
tape.pausing = FALSE;
+ tape.scr_fieldx = SCR_FIELDX_DEFAULT;
+ tape.scr_fieldy = SCR_FIELDY_DEFAULT;
+
tape.no_valid_file = FALSE;
}
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)
{
int level_identifier_size;
{
{ "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 }
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);
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;
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);
TYPE_STRING,
&setup.player_name, "player_name"
},
+ {
+ TYPE_SWITCH,
+ &setup.multiple_users, "multiple_users"
+ },
{
TYPE_SWITCH,
&setup.sound, "sound"
},
{
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.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[] =
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->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->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->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);
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;
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 (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;