X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Ffiles.c;h=75e691c36555fdd434af328a817ac5be0c482c99;hp=83749a573d4f62489989211475bd53dfdf9103b0;hb=17c7213a32d3a0e4c84727937f2ed79028461798;hpb=73cee55038f98c0ef7346d9ea3fbbb4ff787c4d6 diff --git a/src/files.c b/src/files.c index 83749a57..75e691c3 100644 --- a/src/files.c +++ b/src/files.c @@ -18,6 +18,7 @@ #include "files.h" #include "init.h" +#include "screens.h" #include "tools.h" #include "tape.h" #include "config.h" @@ -57,7 +58,7 @@ #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 3 /* unused tape header bytes */ +#define TAPE_CHUNK_HEAD_UNUSED 2 /* 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) @@ -244,6 +245,18 @@ static struct LevelFileConfigInfo chunk_config_INFO[] = &li.auto_exit_sokoban, FALSE }, + { + -1, -1, + TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), + &li.auto_count_gems, FALSE + }, + + { + -1, -1, + TYPE_BOOLEAN, CONF_VALUE_8_BIT(11), + &li.solved_by_one_player, FALSE + }, + { -1, -1, -1, -1, @@ -655,6 +668,11 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] = TYPE_INTEGER, CONF_VALUE_8_BIT(4), &li.game_of_life[3], 3 }, + { + EL_GAME_OF_LIFE, -1, + TYPE_BOOLEAN, CONF_VALUE_8_BIT(5), + &li.use_life_bugs, FALSE + }, { EL_BIOMAZE, -1, @@ -800,16 +818,69 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] = &li.num_ball_contents, 4, MAX_ELEMENT_CONTENTS }, - /* ---------- unused values ----------------------------------------------- */ + { + EL_MM_MCDUFFIN, -1, + TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), + &li.mm_laser_red, FALSE + }, + { + EL_MM_MCDUFFIN, -1, + TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), + &li.mm_laser_green, FALSE + }, + { + EL_MM_MCDUFFIN, -1, + TYPE_BOOLEAN, CONF_VALUE_8_BIT(3), + &li.mm_laser_blue, TRUE + }, { - EL_UNKNOWN, SAVE_CONF_NEVER, + EL_DF_LASER, -1, + TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), + &li.df_laser_red, TRUE + }, + { + EL_DF_LASER, -1, + TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), + &li.df_laser_green, TRUE + }, + { + EL_DF_LASER, -1, + TYPE_BOOLEAN, CONF_VALUE_8_BIT(3), + &li.df_laser_blue, FALSE + }, + + { + EL_MM_FUSE_ACTIVE, -1, + TYPE_INTEGER, CONF_VALUE_16_BIT(1), + &li.mm_time_fuse, 25 + }, + { + EL_MM_BOMB, -1, + TYPE_INTEGER, CONF_VALUE_16_BIT(1), + &li.mm_time_bomb, 75 + }, + { + EL_MM_GRAY_BALL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), - &li.score[SC_UNKNOWN_14], 10 + &li.mm_time_ball, 75 }, + { + EL_MM_STEEL_BLOCK, -1, + TYPE_INTEGER, CONF_VALUE_16_BIT(1), + &li.mm_time_block, 75 + }, + { + EL_MM_LIGHTBALL, -1, + TYPE_INTEGER, CONF_VALUE_16_BIT(1), + &li.score[SC_ELEM_BONUS], 10 + }, + + /* ---------- unused values ----------------------------------------------- */ + { EL_UNKNOWN, SAVE_CONF_NEVER, - TYPE_INTEGER, CONF_VALUE_16_BIT(2), + TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_UNKNOWN_15], 10 }, @@ -1319,6 +1390,8 @@ filetype_id_list[] = { LEVEL_FILE_TYPE_DX, "DX" }, { LEVEL_FILE_TYPE_SB, "SB" }, { LEVEL_FILE_TYPE_DC, "DC" }, + { LEVEL_FILE_TYPE_MM, "MM" }, + { LEVEL_FILE_TYPE_MM, "DF" }, { -1, NULL }, }; @@ -1336,7 +1409,7 @@ static boolean check_special_flags(char *flag) return FALSE; } -static struct DateInfo getCurrentDate() +static struct DateInfo getCurrentDate(void) { time_t epoch_seconds = time(NULL); struct tm *now = localtime(&epoch_seconds); @@ -1359,7 +1432,7 @@ static void resetEventFlags(struct ElementChangeInfo *change) change->has_event[i] = FALSE; } -static void resetEventBits() +static void resetEventBits(void) { int i; @@ -1601,9 +1674,11 @@ static void setLevelInfoToDefaults_Level(struct LevelInfo *level) setLevelInfoToDefaults_EM(); setLevelInfoToDefaults_SP(); + setLevelInfoToDefaults_MM(); level->native_em_level = &native_em_level; level->native_sp_level = &native_sp_level; + level->native_mm_level = &native_mm_level; level->file_version = FILE_VERSION_ACTUAL; level->game_version = GAME_VERSION_ACTUAL; @@ -1634,6 +1709,9 @@ static void setLevelInfoToDefaults_Level(struct LevelInfo *level) BorderElement = EL_STEELWALL; + /* detect custom elements when loading them */ + level->file_has_custom_elements = FALSE; + /* set all bug compatibility flags to "false" => do not emulate this bug */ level->use_action_after_change_bug = FALSE; @@ -1788,13 +1866,14 @@ static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info) level_file_info->nr = 0; level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN; level_file_info->packed = FALSE; - level_file_info->basename = NULL; - level_file_info->filename = NULL; + + setString(&level_file_info->basename, NULL); + setString(&level_file_info->filename, NULL); } int getMappedElement_SB(int, boolean); -static void ActivateLevelTemplate() +static void ActivateLevelTemplate(void) { int x, y; @@ -1847,6 +1926,9 @@ static void ActivateLevelTemplate() /* overwrite all individual level settings from template level settings */ level = level_template; + /* restore level file info */ + level.file_info = level_backup.file_info; + /* restore playfield size */ level.fieldx = level_backup.fieldx; level.fieldy = level_backup.fieldy; @@ -1867,14 +1949,13 @@ static void ActivateLevelTemplate() static char *getLevelFilenameFromBasename(char *basename) { - static char *filename[2] = { NULL, NULL }; - int pos = (strEqual(basename, LEVELTEMPLATE_FILENAME) ? 0 : 1); + static char *filename = NULL; - checked_free(filename[pos]); + checked_free(filename); - filename[pos] = getPath2(getCurrentLevelDir(), basename); + filename = getPath2(getCurrentLevelDir(), basename); - return filename[pos]; + return filename; } static int getFileTypeFromBasename(char *basename) @@ -1915,6 +1996,26 @@ static int getFileTypeFromBasename(char *basename) return LEVEL_FILE_TYPE_UNKNOWN; } +static int getFileTypeFromMagicBytes(char *filename, int type) +{ + File *file; + + if ((file = openFile(filename, MODE_READ))) + { + char chunk_name[CHUNK_ID_LEN + 1]; + + getFileChunkBE(file, chunk_name, NULL); + + if (strEqual(chunk_name, "MMII") || + strEqual(chunk_name, "MIRR")) + type = LEVEL_FILE_TYPE_MM; + + closeFile(file); + } + + return type; +} + static boolean checkForPackageFromBasename(char *basename) { /* !!! WON'T WORK ANYMORE IF getFileTypeFromBasename() ALSO DETECTS !!! @@ -2001,8 +2102,9 @@ static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi, { lfi->type = type; lfi->packed = FALSE; - lfi->basename = getSingleLevelBasename(lfi->nr, lfi->type); - lfi->filename = getLevelFilenameFromBasename(lfi->basename); + + setString(&lfi->basename, getSingleLevelBasename(lfi->nr, lfi->type)); + setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename)); } #endif @@ -2018,8 +2120,9 @@ static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi, lfi->type = type; lfi->packed = FALSE; - lfi->basename = basename; - lfi->filename = getLevelFilenameFromBasename(lfi->basename); + + setString(&lfi->basename, basename); + setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename)); } static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi, @@ -2027,8 +2130,9 @@ static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi, { lfi->type = type; lfi->packed = TRUE; - lfi->basename = getPackedLevelBasename(lfi->type); - lfi->filename = getLevelFilenameFromBasename(lfi->basename); + + setString(&lfi->basename, getPackedLevelBasename(lfi->type)); + setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename)); } static int getFiletypeFromID(char *filetype_id) @@ -2060,12 +2164,12 @@ static int getFiletypeFromID(char *filetype_id) return filetype; } -char *getLocalLevelTemplateFilename() +char *getLocalLevelTemplateFilename(void) { return getDefaultLevelFilename(-1); } -char *getGlobalLevelTemplateFilename() +char *getGlobalLevelTemplateFilename(void) { /* global variable "leveldir_current" must be modified in the loop below */ LevelDirTree *leveldir_current_last = leveldir_current; @@ -2100,7 +2204,7 @@ static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi) getSingleLevelBasename(-1)); /* replace local level template filename with global template filename */ - lfi->filename = getGlobalLevelTemplateFilename(); + setString(&lfi->filename, getGlobalLevelTemplateFilename()); /* no fallback if template file not existing */ return; @@ -2119,6 +2223,16 @@ static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi) if (fileExists(lfi->filename)) return; } + else if (leveldir_current->level_filetype != NULL) + { + int filetype = getFiletypeFromID(leveldir_current->level_filetype); + + /* check for specified native level file with standard file name */ + setLevelFileInfo_FormatLevelFilename(lfi, filetype, + "%03d.%s", nr, LEVELFILE_EXTENSION); + if (fileExists(lfi->filename)) + return; + } /* check for native Rocks'n'Diamonds level file */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND, @@ -2171,6 +2285,9 @@ static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi) { if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN) lfi->type = getFileTypeFromBasename(lfi->basename); + + if (lfi->type == LEVEL_FILE_TYPE_RND) + lfi->type = getFileTypeFromMagicBytes(lfi->filename, lfi->type); } static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr) @@ -2184,11 +2301,22 @@ static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr) determineLevelFileInfo_Filetype(level_file_info); } +static void copyLevelFileInfo(struct LevelFileInfo *lfi_from, + struct LevelFileInfo *lfi_to) +{ + lfi_to->nr = lfi_from->nr; + lfi_to->type = lfi_from->type; + lfi_to->packed = lfi_from->packed; + + setString(&lfi_to->basename, lfi_from->basename); + setString(&lfi_to->filename, lfi_from->filename); +} + /* ------------------------------------------------------------------------- */ /* functions for loading R'n'D level */ /* ------------------------------------------------------------------------- */ -int getMappedElement(int element) +static int getMappedElement(int element) { /* remap some (historic, now obsolete) elements */ @@ -2239,7 +2367,7 @@ int getMappedElement(int element) return element; } -int getMappedElementByVersion(int element, int game_version) +static int getMappedElementByVersion(int element, int game_version) { /* remap some elements due to certain game version */ @@ -2545,6 +2673,8 @@ static int LoadLevel_CUS1(File *file, int chunk_size, struct LevelInfo *level) element_info[element].push_delay_random = 8; } + level->file_has_custom_elements = TRUE; + return chunk_size; } @@ -2571,6 +2701,8 @@ static int LoadLevel_CUS2(File *file, int chunk_size, struct LevelInfo *level) Error(ERR_WARN, "invalid custom element number %d", element); } + level->file_has_custom_elements = TRUE; + return chunk_size; } @@ -2662,6 +2794,8 @@ static int LoadLevel_CUS3(File *file, int chunk_size, struct LevelInfo *level) ei->modified_settings = TRUE; } + level->file_has_custom_elements = TRUE; + return chunk_size; } @@ -2810,6 +2944,8 @@ static int LoadLevel_CUS4(File *file, int chunk_size, struct LevelInfo *level) /* mark this custom element as modified */ ei->modified_settings = TRUE; + level->file_has_custom_elements = TRUE; + return chunk_size; } @@ -2854,6 +2990,8 @@ static int LoadLevel_GRP1(File *file, int chunk_size, struct LevelInfo *level) /* mark this group element as modified */ element_info[element].modified_settings = TRUE; + level->file_has_custom_elements = TRUE; + return chunk_size; } @@ -3146,6 +3284,8 @@ static int LoadLevel_CUSX(File *file, int chunk_size, struct LevelInfo *level) break; } + level->file_has_custom_elements = TRUE; + return real_chunk_size; } @@ -3171,6 +3311,8 @@ static int LoadLevel_GRPX(File *file, int chunk_size, struct LevelInfo *level) *ei = xx_ei; *group = xx_group; + level->file_has_custom_elements = TRUE; + return real_chunk_size; } @@ -3347,7 +3489,7 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level, /* functions for loading EM level */ /* ------------------------------------------------------------------------- */ -void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) +static void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) { static int ball_xy[8][2] = { @@ -3475,7 +3617,7 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) } } -void CopyNativeLevel_EM_to_RND(struct LevelInfo *level) +static void CopyNativeLevel_EM_to_RND(struct LevelInfo *level) { static int ball_xy[8][2] = { @@ -3576,7 +3718,7 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level) /* functions for loading SP level */ /* ------------------------------------------------------------------------- */ -void CopyNativeLevel_RND_to_SP(struct LevelInfo *level) +static void CopyNativeLevel_RND_to_SP(struct LevelInfo *level) { struct LevelInfo_SP *level_sp = level->native_sp_level; LevelInfoType *header = &level_sp->header; @@ -3660,11 +3802,12 @@ void CopyNativeLevel_RND_to_SP(struct LevelInfo *level) } } -void CopyNativeLevel_SP_to_RND(struct LevelInfo *level) +static void CopyNativeLevel_SP_to_RND(struct LevelInfo *level) { struct LevelInfo_SP *level_sp = level->native_sp_level; LevelInfoType *header = &level_sp->header; - int i, x, y; + boolean num_invalid_elements = 0; + int i, j, x, y; level->fieldx = level_sp->width; level->fieldy = level_sp->height; @@ -3677,20 +3820,39 @@ void CopyNativeLevel_SP_to_RND(struct LevelInfo *level) int element_new = getMappedElement(map_element_SP_to_RND(element_old)); if (element_new == EL_UNKNOWN) - Error(ERR_WARN, "invalid element %d at position %d, %d", + { + num_invalid_elements++; + + Error(ERR_DEBUG, "invalid element %d at position %d, %d", element_old, x, y); + } level->field[x][y] = element_new; } } + if (num_invalid_elements > 0) + Error(ERR_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] = (header->InitialGravity == 1 ? TRUE : FALSE); + /* skip leading spaces */ for (i = 0; i < SP_LEVEL_NAME_LEN; i++) - level->name[i] = header->LevelTitle[i]; - level->name[SP_LEVEL_NAME_LEN] = '\0'; + if (header->LevelTitle[i] != ' ') + break; + + /* copy level title */ + for (j = 0; i < SP_LEVEL_NAME_LEN; i++, j++) + level->name[j] = header->LevelTitle[i]; + level->name[j] = '\0'; + + /* cut trailing spaces */ + for (; j > 0; j--) + if (level->name[j - 1] == ' ' && level->name[j] == '\0') + level->name[j - 1] = '\0'; level->gems_needed = header->InfotronsNeeded; @@ -3800,7 +3962,7 @@ static void CopyNativeTape_RND_to_SP(struct LevelInfo *level) demo->is_available = TRUE; } -static void setTapeInfoToDefaults(); +static void setTapeInfoToDefaults(void); static void CopyNativeTape_SP_to_RND(struct LevelInfo *level) { @@ -3820,8 +3982,8 @@ static void CopyNativeTape_SP_to_RND(struct LevelInfo *level) TapeSetDateFromEpochSeconds(getFileTimestampEpochSeconds(filename)); - tape.length = 0; - tape.pos[tape.length].delay = 0; + tape.counter = 0; + tape.pos[tape.counter].delay = 0; for (i = 0; i < demo->length; i++) { @@ -3829,41 +3991,104 @@ static void CopyNativeTape_SP_to_RND(struct LevelInfo *level) int demo_repeat = (demo->data[i] & 0xf0) >> 4; int tape_action = map_key_SP_to_RND(demo_action); int tape_repeat = demo_repeat + 1; - int tape_entries = 1; // one new tape entry may be added + byte action[MAX_PLAYERS] = { tape_action, 0, 0, 0 }; + boolean success = 0; + int j; + + for (j = 0; j < tape_repeat; j++) + success = TapeAddAction(action); - if (tape.length + tape_entries >= MAX_TAPE_LEN) + if (!success) { Error(ERR_WARN, "SP demo truncated: size exceeds maximum tape size %d", MAX_TAPE_LEN); break; } + } - if (tape.pos[tape.length].delay > 0) /* already stored action */ - { - if (tape.pos[tape.length].action[0] != tape_action || - tape.pos[tape.length].delay + tape_repeat >= 256) - { - tape.length++; - tape.pos[tape.length].delay = 0; - } - else - { - tape.pos[tape.length].delay += tape_repeat; - } - } + TapeHaltRecording(); +} - if (tape.pos[tape.length].delay == 0) /* store new action */ - { - tape.pos[tape.length].action[0] = tape_action; - tape.pos[tape.length].delay = tape_repeat; - } - } - tape.length++; +/* ------------------------------------------------------------------------- */ +/* functions for loading MM level */ +/* ------------------------------------------------------------------------- */ - tape.length_frames = GetTapeLengthFrames(); - tape.length_seconds = GetTapeLengthSeconds(); +static void CopyNativeLevel_RND_to_MM(struct LevelInfo *level) +{ + struct LevelInfo_MM *level_mm = level->native_mm_level; + int x, y; + + level_mm->fieldx = MIN(level->fieldx, MM_MAX_PLAYFIELD_WIDTH); + level_mm->fieldy = MIN(level->fieldy, MM_MAX_PLAYFIELD_HEIGHT); + + level_mm->time = level->time; + level_mm->kettles_needed = level->gems_needed; + level_mm->auto_count_kettles = level->auto_count_gems; + + level_mm->laser_red = level->mm_laser_red; + level_mm->laser_green = level->mm_laser_green; + level_mm->laser_blue = level->mm_laser_blue; + + strcpy(level_mm->name, level->name); + strcpy(level_mm->author, level->author); + + level_mm->score[SC_EMERALD] = level->score[SC_EMERALD]; + level_mm->score[SC_PACMAN] = level->score[SC_PACMAN]; + level_mm->score[SC_KEY] = level->score[SC_KEY]; + level_mm->score[SC_TIME_BONUS] = level->score[SC_TIME_BONUS]; + level_mm->score[SC_ELEM_BONUS] = level->score[SC_ELEM_BONUS]; + + level_mm->amoeba_speed = level->amoeba_speed; + level_mm->time_fuse = level->mm_time_fuse; + level_mm->time_bomb = level->mm_time_bomb; + level_mm->time_ball = level->mm_time_ball; + level_mm->time_block = level->mm_time_block; + + for (x = 0; x < level->fieldx; x++) + for (y = 0; y < level->fieldy; y++) + Ur[x][y] = + level_mm->field[x][y] = map_element_RND_to_MM(level->field[x][y]); +} + +static void CopyNativeLevel_MM_to_RND(struct LevelInfo *level) +{ + struct LevelInfo_MM *level_mm = level->native_mm_level; + int x, y; + + level->fieldx = MIN(level_mm->fieldx, MAX_LEV_FIELDX); + level->fieldy = MIN(level_mm->fieldy, MAX_LEV_FIELDY); + + level->time = level_mm->time; + level->gems_needed = level_mm->kettles_needed; + level->auto_count_gems = level_mm->auto_count_kettles; + + level->mm_laser_red = level_mm->laser_red; + level->mm_laser_green = level_mm->laser_green; + level->mm_laser_blue = level_mm->laser_blue; + + strcpy(level->name, level_mm->name); + + /* only overwrite author from 'levelinfo.conf' if author defined in level */ + if (!strEqual(level_mm->author, ANONYMOUS_NAME)) + strcpy(level->author, level_mm->author); + + level->score[SC_EMERALD] = level_mm->score[SC_EMERALD]; + level->score[SC_PACMAN] = level_mm->score[SC_PACMAN]; + level->score[SC_KEY] = level_mm->score[SC_KEY]; + level->score[SC_TIME_BONUS] = level_mm->score[SC_TIME_BONUS]; + level->score[SC_ELEM_BONUS] = level_mm->score[SC_ELEM_BONUS]; + + level->amoeba_speed = level_mm->amoeba_speed; + level->mm_time_fuse = level_mm->time_fuse; + level->mm_time_bomb = level_mm->time_bomb; + level->mm_time_ball = level_mm->time_ball; + level->mm_time_block = level_mm->time_block; + + for (x = 0; x < level->fieldx; x++) + for (y = 0; y < level->fieldy; y++) + level->field[x][y] = map_element_MM_to_RND(level_mm->field[x][y]); } @@ -3873,7 +4098,8 @@ static void CopyNativeTape_SP_to_RND(struct LevelInfo *level) #define DC_LEVEL_HEADER_SIZE 344 -unsigned short getDecodedWord_DC(unsigned short data_encoded, boolean init) +static unsigned short getDecodedWord_DC(unsigned short data_encoded, + boolean init) { static int last_data_encoded; static int offset1; @@ -3912,7 +4138,7 @@ unsigned short getDecodedWord_DC(unsigned short data_encoded, boolean init) return data_decoded; } -int getMappedElement_DC(int element) +static int getMappedElement_DC(int element) { switch (element) { @@ -5896,12 +6122,22 @@ static void LoadLevelFromFileInfo_SP(struct LevelInfo *level, level->no_valid_file = TRUE; } +static void LoadLevelFromFileInfo_MM(struct LevelInfo *level, + struct LevelFileInfo *level_file_info, + boolean level_info_only) +{ + if (!LoadNativeLevel_MM(level_file_info->filename, level_info_only)) + level->no_valid_file = TRUE; +} + void CopyNativeLevel_RND_to_Native(struct LevelInfo *level) { if (level->game_engine_type == GAME_ENGINE_TYPE_EM) CopyNativeLevel_RND_to_EM(level); else if (level->game_engine_type == GAME_ENGINE_TYPE_SP) CopyNativeLevel_RND_to_SP(level); + else if (level->game_engine_type == GAME_ENGINE_TYPE_MM) + CopyNativeLevel_RND_to_MM(level); } void CopyNativeLevel_Native_to_RND(struct LevelInfo *level) @@ -5910,6 +6146,8 @@ void CopyNativeLevel_Native_to_RND(struct LevelInfo *level) CopyNativeLevel_EM_to_RND(level); else if (level->game_engine_type == GAME_ENGINE_TYPE_SP) CopyNativeLevel_SP_to_RND(level); + else if (level->game_engine_type == GAME_ENGINE_TYPE_MM) + CopyNativeLevel_MM_to_RND(level); } void SaveNativeLevel(struct LevelInfo *level) @@ -5954,6 +6192,11 @@ static void LoadLevelFromFileInfo(struct LevelInfo *level, level->game_engine_type = GAME_ENGINE_TYPE_SP; break; + case LEVEL_FILE_TYPE_MM: + LoadLevelFromFileInfo_MM(level, level_file_info, level_info_only); + level->game_engine_type = GAME_ENGINE_TYPE_MM; + break; + case LEVEL_FILE_TYPE_DC: LoadLevelFromFileInfo_DC(level, level_file_info, level_info_only); break; @@ -5987,12 +6230,13 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename) level_file_info.nr = 0; /* unknown level number */ level_file_info.type = LEVEL_FILE_TYPE_RND; /* no others supported yet */ - level_file_info.filename = filename; + + setString(&level_file_info.filename, filename); LoadLevelFromFileInfo(level, &level_file_info, FALSE); } -static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) +static void LoadLevel_InitVersion(struct LevelInfo *level) { int i, j; @@ -6070,6 +6314,10 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) level->extra_time_score = level->score[SC_TIME_BONUS]; } + /* game logic of "game of life" and "biomaze" was buggy before 4.1.1.1 */ + if (level->game_version < VERSION_IDENT(4,1,1,1)) + level->use_life_bugs = TRUE; + if (level->game_version < VERSION_IDENT(3,2,0,7)) { /* default behaviour for snapping was "not continuous" before 3.2.0-7 */ @@ -6163,11 +6411,31 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) /* EM style elements always chain-exploded in R'n'D engine before 3.2.6 */ if (level->game_version < VERSION_IDENT(3,2,6,0)) level->em_explodes_by_fire = TRUE; + + /* levels were solved by the first player entering an exit up to 4.1.0.0 */ + if (level->game_version <= VERSION_IDENT(4,1,0,0)) + level->solved_by_one_player = TRUE; } -static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) +static void LoadLevel_InitStandardElements(struct LevelInfo *level) { - int i, j, x, y; + int i, x, y; + + /* map elements that have changed in newer versions */ + level->amoeba_content = getMappedElementByVersion(level->amoeba_content, + level->game_version); + for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) + for (x = 0; x < 3; x++) + for (y = 0; y < 3; y++) + level->yamyam_content[i].e[x][y] = + getMappedElementByVersion(level->yamyam_content[i].e[x][y], + level->game_version); + +} + +static void LoadLevel_InitCustomElements(struct LevelInfo *level) +{ + int i, j; /* map custom element change events that have changed in newer versions (these following values were accidentally changed in version 3.0.1) @@ -6281,23 +6549,34 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) } } - /* map elements that have changed in newer versions */ - level->amoeba_content = getMappedElementByVersion(level->amoeba_content, - level->game_version); - for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) - for (x = 0; x < 3; x++) - for (y = 0; y < 3; y++) - level->yamyam_content[i].e[x][y] = - getMappedElementByVersion(level->yamyam_content[i].e[x][y], - level->game_version); + /* set some other uninitialized values of custom elements in older levels */ + if (level->game_version < VERSION_IDENT(3,1,0,0)) + { + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + + element_info[element].access_direction = MV_ALL_DIRECTIONS; + + element_info[element].explosion_delay = 17; + element_info[element].ignition_delay = 8; + } + } +} + +static void LoadLevel_InitElements(struct LevelInfo *level) +{ + LoadLevel_InitStandardElements(level); + + if (level->file_has_custom_elements) + LoadLevel_InitCustomElements(level); /* initialize element properties for level editor etc. */ InitElementPropertiesEngine(level->game_version); - InitElementPropertiesAfterLoading(level->game_version); InitElementPropertiesGfxElement(); } -static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename) +static void LoadLevel_InitPlayfield(struct LevelInfo *level) { int x, y; @@ -6329,7 +6608,7 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename) SetBorderElement(); } -static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename) +static void LoadLevel_InitNativeEngines(struct LevelInfo *level) { struct LevelFileInfo *level_file_info = &level->file_info; @@ -6337,38 +6616,63 @@ static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename) CopyNativeLevel_RND_to_Native(level); } -void LoadLevelTemplate(int nr) +static void LoadLevelTemplate_LoadAndInit(void) { - char *filename; - - setLevelFileInfo(&level_template.file_info, nr); - filename = level_template.file_info.filename; - LoadLevelFromFileInfo(&level_template, &level_template.file_info, FALSE); - LoadLevel_InitVersion(&level_template, filename); - LoadLevel_InitElements(&level_template, filename); + LoadLevel_InitVersion(&level_template); + LoadLevel_InitElements(&level_template); ActivateLevelTemplate(); } -void LoadLevel(int nr) +void LoadLevelTemplate(int nr) { - char *filename; + if (!fileExists(getGlobalLevelTemplateFilename())) + { + Error(ERR_WARN, "no level template found for this level"); - setLevelFileInfo(&level.file_info, nr); - filename = level.file_info.filename; + return; + } + setLevelFileInfo(&level_template.file_info, nr); + + LoadLevelTemplate_LoadAndInit(); +} + +static void LoadNetworkLevelTemplate(struct NetworkLevelInfo *network_level) +{ + copyLevelFileInfo(&network_level->tmpl_info, &level_template.file_info); + + LoadLevelTemplate_LoadAndInit(); +} + +static void LoadLevel_LoadAndInit(struct NetworkLevelInfo *network_level) +{ LoadLevelFromFileInfo(&level, &level.file_info, FALSE); if (level.use_custom_template) - LoadLevelTemplate(-1); + { + if (network_level != NULL) + LoadNetworkLevelTemplate(network_level); + else + LoadLevelTemplate(-1); + } - LoadLevel_InitVersion(&level, filename); - LoadLevel_InitElements(&level, filename); - LoadLevel_InitPlayfield(&level, filename); + LoadLevel_InitVersion(&level); + LoadLevel_InitElements(&level); + LoadLevel_InitPlayfield(&level); - LoadLevel_InitNativeEngines(&level, filename); + LoadLevel_InitNativeEngines(&level); +} + +void LoadLevel(int nr) +{ + SetLevelSetInfo(leveldir_current->identifier, nr); + + setLevelFileInfo(&level.file_info, nr); + + LoadLevel_LoadAndInit(NULL); } void LoadLevelInfoOnly(int nr) @@ -6378,6 +6682,16 @@ void LoadLevelInfoOnly(int nr) LoadLevelFromFileInfo(&level, &level.file_info, TRUE); } +void LoadNetworkLevel(struct NetworkLevelInfo *network_level) +{ + SetLevelSetInfo(network_level->leveldir_identifier, + network_level->file_info.nr); + + copyLevelFileInfo(&network_level->file_info, &level.file_info); + + LoadLevel_LoadAndInit(network_level); +} + static int SaveLevel_VERS(FILE *file, struct LevelInfo *level) { int chunk_size = 0; @@ -7210,7 +7524,7 @@ void SaveLevel(int nr) SaveLevelFromFilename(&level, filename, FALSE); } -void SaveLevelTemplate() +void SaveLevelTemplate(void) { char *filename = getLocalLevelTemplateFilename(); @@ -7280,7 +7594,7 @@ void DumpLevel(struct LevelInfo *level) /* tape file functions */ /* ========================================================================= */ -static void setTapeInfoToDefaults() +static void setTapeInfoToDefaults(void) { int i; @@ -7341,6 +7655,8 @@ static int LoadTape_HEAD(File *file, int chunk_size, struct TapeInfo *tape) } } + tape->use_mouse = (getFile8Bit(file) == 1 ? TRUE : FALSE); + ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED); engine_version = getFileVersion(file); @@ -7376,8 +7692,9 @@ static int LoadTape_INFO(File *file, int chunk_size, struct TapeInfo *tape) static int LoadTape_BODY(File *file, int chunk_size, struct TapeInfo *tape) { int i, j; - int chunk_size_expected = - (tape->num_participating_players + 1) * tape->length; + int tape_pos_size = + (tape->use_mouse ? 3 : tape->num_participating_players) + 1; + int chunk_size_expected = tape_pos_size * tape->length; if (chunk_size_expected != chunk_size) { @@ -7388,14 +7705,34 @@ static int LoadTape_BODY(File *file, int chunk_size, struct TapeInfo *tape) for (i = 0; i < tape->length; i++) { if (i >= MAX_TAPE_LEN) + { + Error(ERR_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); + break; + } - for (j = 0; j < MAX_PLAYERS; j++) + if (tape->use_mouse) { - tape->pos[i].action[j] = MV_NONE; + 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); - if (tape->player_participates[j]) - tape->pos[i].action[j] = getFile8Bit(file); + tape->pos[i].action[TAPE_ACTION_UNUSED] = 0; + } + else + { + for (j = 0; j < MAX_PLAYERS; j++) + { + tape->pos[i].action[j] = MV_NONE; + + if (tape->player_participates[j]) + tape->pos[i].action[j] = getFile8Bit(file); + } } tape->pos[i].delay = getFile8Bit(file); @@ -7452,12 +7789,12 @@ static int LoadTape_BODY(File *file, int chunk_size, struct TapeInfo *tape) } if (i != tape->length) - chunk_size = (tape->num_participating_players + 1) * i; + chunk_size = tape_pos_size * i; return chunk_size; } -void LoadTape_SokobanSolution(char *filename) +static void LoadTape_SokobanSolution(char *filename) { File *file; int move_delay = TILESIZE / level.initial_player_stepsize[0]; @@ -7721,6 +8058,8 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape) putFile8Bit(file, store_participating_players); + putFile8Bit(file, (tape->use_mouse ? 1 : 0)); + /* unused bytes not at the end here for 4-byte alignment of engine_version */ WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED); @@ -7746,9 +8085,18 @@ static void SaveTape_BODY(FILE *file, struct TapeInfo *tape) for (i = 0; i < tape->length; i++) { - for (j = 0; j < MAX_PLAYERS; j++) - if (tape->player_participates[j]) - putFile8Bit(file, tape->pos[i].action[j]); + 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 + { + for (j = 0; j < MAX_PLAYERS; j++) + if (tape->player_participates[j]) + putFile8Bit(file, tape->pos[i].action[j]); + } putFile8Bit(file, tape->pos[i].delay); } @@ -7759,6 +8107,7 @@ void SaveTape(int nr) 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; @@ -7779,8 +8128,10 @@ void SaveTape(int nr) if (tape.player_participates[i]) num_participating_players++; + tape_pos_size = (tape.use_mouse ? 3 : num_participating_players) + 1; + info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2; - body_chunk_size = (num_participating_players + 1) * tape.length; + body_chunk_size = tape_pos_size * tape.length; putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED); putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE); @@ -7804,18 +8155,18 @@ void SaveTape(int nr) tape.changed = FALSE; } -boolean SaveTapeChecked(int nr) +static boolean SaveTapeCheckedExt(int nr, char *msg_replace, char *msg_saved) { char *filename = getTapeFilename(nr); boolean new_tape = !fileExists(filename); boolean tape_saved = FALSE; - if (new_tape || Request("Replace old tape?", REQ_ASK)) + if (new_tape || Request(msg_replace, REQ_ASK)) { SaveTape(nr); if (new_tape) - Request("Tape saved!", REQ_CONFIRM); + Request(msg_saved, REQ_CONFIRM); tape_saved = TRUE; } @@ -7823,6 +8174,17 @@ boolean SaveTapeChecked(int nr) return tape_saved; } +boolean SaveTapeChecked(int nr) +{ + return SaveTapeCheckedExt(nr, "Replace old tape?", "Tape saved!"); +} + +boolean SaveTapeChecked_LevelSolved(int nr) +{ + return SaveTapeCheckedExt(nr, "Level solved! Replace old tape?", + "Level solved! Tape saved!"); +} + void DumpTape(struct TapeInfo *tape) { int tape_frame_counter; @@ -7946,7 +8308,8 @@ void SaveScore(int nr) char *filename = getScoreFilename(nr); FILE *file; - InitScoreDirectory(leveldir_current->subdir); + /* used instead of "leveldir_current->subdir" (for network games) */ + InitScoreDirectory(levelset.identifier); if (!(file = fopen(filename, MODE_WRITE))) { @@ -7972,191 +8335,242 @@ void SaveScore(int nr) #define TOKEN_STR_PLAYER_PREFIX "player_" /* global setup */ -#define SETUP_TOKEN_PLAYER_NAME 0 -#define SETUP_TOKEN_SOUND 1 -#define SETUP_TOKEN_SOUND_LOOPS 2 -#define SETUP_TOKEN_SOUND_MUSIC 3 -#define SETUP_TOKEN_SOUND_SIMPLE 4 -#define SETUP_TOKEN_TOONS 5 -#define SETUP_TOKEN_SCROLL_DELAY 6 -#define SETUP_TOKEN_SCROLL_DELAY_VALUE 7 -#define SETUP_TOKEN_ENGINE_SNAPSHOT_MODE 8 -#define SETUP_TOKEN_ENGINE_SNAPSHOT_MEMORY 9 -#define SETUP_TOKEN_FADE_SCREENS 10 -#define SETUP_TOKEN_AUTORECORD 11 -#define SETUP_TOKEN_SHOW_TITLESCREEN 12 -#define SETUP_TOKEN_QUICK_DOORS 13 -#define SETUP_TOKEN_TEAM_MODE 14 -#define SETUP_TOKEN_HANDICAP 15 -#define SETUP_TOKEN_SKIP_LEVELS 16 -#define SETUP_TOKEN_INCREMENT_LEVELS 17 -#define SETUP_TOKEN_TIME_LIMIT 18 -#define SETUP_TOKEN_FULLSCREEN 19 -#define SETUP_TOKEN_WINDOW_SCALING_PERCENT 20 -#define SETUP_TOKEN_WINDOW_SCALING_QUALITY 21 -#define SETUP_TOKEN_SCREEN_RENDERING_MODE 22 -#define SETUP_TOKEN_ASK_ON_ESCAPE 23 -#define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR 24 -#define SETUP_TOKEN_QUICK_SWITCH 25 -#define SETUP_TOKEN_INPUT_ON_FOCUS 26 -#define SETUP_TOKEN_PREFER_AGA_GRAPHICS 27 -#define SETUP_TOKEN_GAME_FRAME_DELAY 28 -#define SETUP_TOKEN_SP_SHOW_BORDER_ELEMENTS 29 -#define SETUP_TOKEN_SMALL_GAME_GRAPHICS 30 -#define SETUP_TOKEN_SHOW_SNAPSHOT_BUTTONS 31 -#define SETUP_TOKEN_GRAPHICS_SET 32 -#define SETUP_TOKEN_SOUNDS_SET 33 -#define SETUP_TOKEN_MUSIC_SET 34 -#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 35 -#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 36 -#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 37 -#define SETUP_TOKEN_VOLUME_SIMPLE 38 -#define SETUP_TOKEN_VOLUME_LOOPS 39 -#define SETUP_TOKEN_VOLUME_MUSIC 40 -#define SETUP_TOKEN_TOUCH_CONTROL_TYPE 41 -#define SETUP_TOKEN_TOUCH_MOVE_DISTANCE 42 -#define SETUP_TOKEN_TOUCH_DROP_DISTANCE 43 - -#define NUM_GLOBAL_SETUP_TOKENS 44 +enum +{ + SETUP_TOKEN_PLAYER_NAME = 0, + SETUP_TOKEN_SOUND, + SETUP_TOKEN_SOUND_LOOPS, + SETUP_TOKEN_SOUND_MUSIC, + SETUP_TOKEN_SOUND_SIMPLE, + SETUP_TOKEN_TOONS, + SETUP_TOKEN_SCROLL_DELAY, + SETUP_TOKEN_SCROLL_DELAY_VALUE, + SETUP_TOKEN_ENGINE_SNAPSHOT_MODE, + SETUP_TOKEN_ENGINE_SNAPSHOT_MEMORY, + SETUP_TOKEN_FADE_SCREENS, + SETUP_TOKEN_AUTORECORD, + SETUP_TOKEN_SHOW_TITLESCREEN, + SETUP_TOKEN_QUICK_DOORS, + SETUP_TOKEN_TEAM_MODE, + SETUP_TOKEN_HANDICAP, + SETUP_TOKEN_SKIP_LEVELS, + SETUP_TOKEN_INCREMENT_LEVELS, + SETUP_TOKEN_AUTO_PLAY_NEXT_LEVEL, + SETUP_TOKEN_SKIP_SCORES_AFTER_GAME, + SETUP_TOKEN_TIME_LIMIT, + SETUP_TOKEN_FULLSCREEN, + SETUP_TOKEN_WINDOW_SCALING_PERCENT, + SETUP_TOKEN_WINDOW_SCALING_QUALITY, + SETUP_TOKEN_SCREEN_RENDERING_MODE, + SETUP_TOKEN_VSYNC_MODE, + SETUP_TOKEN_ASK_ON_ESCAPE, + SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR, + SETUP_TOKEN_ASK_ON_GAME_OVER, + SETUP_TOKEN_QUICK_SWITCH, + SETUP_TOKEN_INPUT_ON_FOCUS, + SETUP_TOKEN_PREFER_AGA_GRAPHICS, + SETUP_TOKEN_GAME_SPEED_EXTENDED, + SETUP_TOKEN_GAME_FRAME_DELAY, + SETUP_TOKEN_SP_SHOW_BORDER_ELEMENTS, + SETUP_TOKEN_SMALL_GAME_GRAPHICS, + SETUP_TOKEN_SHOW_SNAPSHOT_BUTTONS, + SETUP_TOKEN_GRAPHICS_SET, + SETUP_TOKEN_SOUNDS_SET, + SETUP_TOKEN_MUSIC_SET, + SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS, + SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS, + SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC, + SETUP_TOKEN_VOLUME_SIMPLE, + SETUP_TOKEN_VOLUME_LOOPS, + SETUP_TOKEN_VOLUME_MUSIC, + SETUP_TOKEN_NETWORK_MODE, + SETUP_TOKEN_NETWORK_PLAYER_NR, + SETUP_TOKEN_NETWORK_SERVER_HOSTNAME, + SETUP_TOKEN_TOUCH_CONTROL_TYPE, + SETUP_TOKEN_TOUCH_MOVE_DISTANCE, + SETUP_TOKEN_TOUCH_DROP_DISTANCE, + SETUP_TOKEN_TOUCH_TRANSPARENCY, + SETUP_TOKEN_TOUCH_DRAW_OUTLINED, + SETUP_TOKEN_TOUCH_DRAW_PRESSED, + SETUP_TOKEN_TOUCH_GRID_XSIZE_0, + SETUP_TOKEN_TOUCH_GRID_YSIZE_0, + SETUP_TOKEN_TOUCH_GRID_XSIZE_1, + SETUP_TOKEN_TOUCH_GRID_YSIZE_1, + + NUM_GLOBAL_SETUP_TOKENS +}; + +/* auto setup */ +enum +{ + SETUP_TOKEN_AUTO_EDITOR_ZOOM_TILESIZE = 0, + + NUM_AUTO_SETUP_TOKENS +}; /* editor setup */ -#define SETUP_TOKEN_EDITOR_EL_CLASSIC 0 -#define SETUP_TOKEN_EDITOR_EL_CUSTOM 1 -#define SETUP_TOKEN_EDITOR_EL_USER_DEFINED 2 -#define SETUP_TOKEN_EDITOR_EL_DYNAMIC 3 -#define SETUP_TOKEN_EDITOR_EL_HEADLINES 4 -#define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN 5 +enum +{ + SETUP_TOKEN_EDITOR_EL_CLASSIC = 0, + SETUP_TOKEN_EDITOR_EL_CUSTOM, + SETUP_TOKEN_EDITOR_EL_USER_DEFINED, + SETUP_TOKEN_EDITOR_EL_DYNAMIC, + SETUP_TOKEN_EDITOR_EL_HEADLINES, + SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN, -#define NUM_EDITOR_SETUP_TOKENS 6 + NUM_EDITOR_SETUP_TOKENS +}; /* 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_STEELTEXT 9 -#define SETUP_TOKEN_EDITOR_CASCADE_CE 10 -#define SETUP_TOKEN_EDITOR_CASCADE_GE 11 -#define SETUP_TOKEN_EDITOR_CASCADE_REF 12 -#define SETUP_TOKEN_EDITOR_CASCADE_USER 13 -#define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC 14 - -#define NUM_EDITOR_CASCADE_SETUP_TOKENS 15 +enum +{ + SETUP_TOKEN_EDITOR_CASCADE_BD = 0, + SETUP_TOKEN_EDITOR_CASCADE_EM, + SETUP_TOKEN_EDITOR_CASCADE_EMC, + SETUP_TOKEN_EDITOR_CASCADE_RND, + SETUP_TOKEN_EDITOR_CASCADE_SB, + SETUP_TOKEN_EDITOR_CASCADE_SP, + SETUP_TOKEN_EDITOR_CASCADE_DC, + SETUP_TOKEN_EDITOR_CASCADE_DX, + SETUP_TOKEN_EDITOR_CASCADE_TEXT, + SETUP_TOKEN_EDITOR_CASCADE_STEELTEXT, + SETUP_TOKEN_EDITOR_CASCADE_CE, + SETUP_TOKEN_EDITOR_CASCADE_GE, + SETUP_TOKEN_EDITOR_CASCADE_REF, + SETUP_TOKEN_EDITOR_CASCADE_USER, + SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC, + + NUM_EDITOR_CASCADE_SETUP_TOKENS +}; /* 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 SETUP_TOKEN_SHORTCUT_TAPE_EJECT 8 -#define SETUP_TOKEN_SHORTCUT_TAPE_EXTRA 9 -#define SETUP_TOKEN_SHORTCUT_TAPE_STOP 10 -#define SETUP_TOKEN_SHORTCUT_TAPE_PAUSE 11 -#define SETUP_TOKEN_SHORTCUT_TAPE_RECORD 12 -#define SETUP_TOKEN_SHORTCUT_TAPE_PLAY 13 -#define SETUP_TOKEN_SHORTCUT_SOUND_SIMPLE 14 -#define SETUP_TOKEN_SHORTCUT_SOUND_LOOPS 15 -#define SETUP_TOKEN_SHORTCUT_SOUND_MUSIC 16 -#define SETUP_TOKEN_SHORTCUT_SNAP_LEFT 17 -#define SETUP_TOKEN_SHORTCUT_SNAP_RIGHT 18 -#define SETUP_TOKEN_SHORTCUT_SNAP_UP 19 -#define SETUP_TOKEN_SHORTCUT_SNAP_DOWN 20 - -#define NUM_SHORTCUT_SETUP_TOKENS 21 +enum +{ + SETUP_TOKEN_SHORTCUT_SAVE_GAME = 0, + SETUP_TOKEN_SHORTCUT_LOAD_GAME, + SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE, + SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1, + SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2, + SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3, + SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4, + SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL, + SETUP_TOKEN_SHORTCUT_TAPE_EJECT, + SETUP_TOKEN_SHORTCUT_TAPE_EXTRA, + SETUP_TOKEN_SHORTCUT_TAPE_STOP, + SETUP_TOKEN_SHORTCUT_TAPE_PAUSE, + SETUP_TOKEN_SHORTCUT_TAPE_RECORD, + SETUP_TOKEN_SHORTCUT_TAPE_PLAY, + SETUP_TOKEN_SHORTCUT_SOUND_SIMPLE, + SETUP_TOKEN_SHORTCUT_SOUND_LOOPS, + SETUP_TOKEN_SHORTCUT_SOUND_MUSIC, + SETUP_TOKEN_SHORTCUT_SNAP_LEFT, + SETUP_TOKEN_SHORTCUT_SNAP_RIGHT, + SETUP_TOKEN_SHORTCUT_SNAP_UP, + SETUP_TOKEN_SHORTCUT_SNAP_DOWN, + + NUM_SHORTCUT_SETUP_TOKENS +}; /* player setup */ -#define SETUP_TOKEN_PLAYER_USE_JOYSTICK 0 -#define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME 1 -#define SETUP_TOKEN_PLAYER_JOY_XLEFT 2 -#define SETUP_TOKEN_PLAYER_JOY_XMIDDLE 3 -#define SETUP_TOKEN_PLAYER_JOY_XRIGHT 4 -#define SETUP_TOKEN_PLAYER_JOY_YUPPER 5 -#define SETUP_TOKEN_PLAYER_JOY_YMIDDLE 6 -#define SETUP_TOKEN_PLAYER_JOY_YLOWER 7 -#define SETUP_TOKEN_PLAYER_JOY_SNAP 8 -#define SETUP_TOKEN_PLAYER_JOY_DROP 9 -#define SETUP_TOKEN_PLAYER_KEY_LEFT 10 -#define SETUP_TOKEN_PLAYER_KEY_RIGHT 11 -#define SETUP_TOKEN_PLAYER_KEY_UP 12 -#define SETUP_TOKEN_PLAYER_KEY_DOWN 13 -#define SETUP_TOKEN_PLAYER_KEY_SNAP 14 -#define SETUP_TOKEN_PLAYER_KEY_DROP 15 - -#define NUM_PLAYER_SETUP_TOKENS 16 +enum +{ + SETUP_TOKEN_PLAYER_USE_JOYSTICK = 0, + SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME, + SETUP_TOKEN_PLAYER_JOY_XLEFT, + SETUP_TOKEN_PLAYER_JOY_XMIDDLE, + SETUP_TOKEN_PLAYER_JOY_XRIGHT, + SETUP_TOKEN_PLAYER_JOY_YUPPER, + SETUP_TOKEN_PLAYER_JOY_YMIDDLE, + SETUP_TOKEN_PLAYER_JOY_YLOWER, + SETUP_TOKEN_PLAYER_JOY_SNAP, + SETUP_TOKEN_PLAYER_JOY_DROP, + SETUP_TOKEN_PLAYER_KEY_LEFT, + SETUP_TOKEN_PLAYER_KEY_RIGHT, + SETUP_TOKEN_PLAYER_KEY_UP, + SETUP_TOKEN_PLAYER_KEY_DOWN, + SETUP_TOKEN_PLAYER_KEY_SNAP, + SETUP_TOKEN_PLAYER_KEY_DROP, + + NUM_PLAYER_SETUP_TOKENS +}; /* system setup */ -#define SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER 0 -#define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER 1 -#define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 2 +enum +{ + SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER = 0, + SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER, + SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE, -#define NUM_SYSTEM_SETUP_TOKENS 3 + NUM_SYSTEM_SETUP_TOKENS +}; /* internal setup */ -#define SETUP_TOKEN_INT_PROGRAM_TITLE 0 -#define SETUP_TOKEN_INT_PROGRAM_VERSION 1 -#define SETUP_TOKEN_INT_PROGRAM_AUTHOR 2 -#define SETUP_TOKEN_INT_PROGRAM_EMAIL 3 -#define SETUP_TOKEN_INT_PROGRAM_WEBSITE 4 -#define SETUP_TOKEN_INT_PROGRAM_COPYRIGHT 5 -#define SETUP_TOKEN_INT_PROGRAM_COMPANY 6 -#define SETUP_TOKEN_INT_PROGRAM_ICON_FILE 7 -#define SETUP_TOKEN_INT_DEFAULT_GRAPHICS_SET 8 -#define SETUP_TOKEN_INT_DEFAULT_SOUNDS_SET 9 -#define SETUP_TOKEN_INT_DEFAULT_MUSIC_SET 10 -#define SETUP_TOKEN_INT_FALLBACK_GRAPHICS_FILE 11 -#define SETUP_TOKEN_INT_FALLBACK_SOUNDS_FILE 12 -#define SETUP_TOKEN_INT_FALLBACK_MUSIC_FILE 13 -#define SETUP_TOKEN_INT_DEFAULT_LEVEL_SERIES 14 -#define SETUP_TOKEN_INT_CHOOSE_FROM_TOP_LEVELDIR 15 -#define SETUP_TOKEN_INT_SHOW_SCALING_IN_TITLE 16 -#define SETUP_TOKEN_INT_DEFAULT_WINDOW_WIDTH 17 -#define SETUP_TOKEN_INT_DEFAULT_WINDOW_HEIGHT 18 - -#define NUM_INTERNAL_SETUP_TOKENS 19 +enum +{ + SETUP_TOKEN_INT_PROGRAM_TITLE = 0, + SETUP_TOKEN_INT_PROGRAM_VERSION, + SETUP_TOKEN_INT_PROGRAM_AUTHOR, + SETUP_TOKEN_INT_PROGRAM_EMAIL, + SETUP_TOKEN_INT_PROGRAM_WEBSITE, + SETUP_TOKEN_INT_PROGRAM_COPYRIGHT, + SETUP_TOKEN_INT_PROGRAM_COMPANY, + SETUP_TOKEN_INT_PROGRAM_ICON_FILE, + SETUP_TOKEN_INT_DEFAULT_GRAPHICS_SET, + SETUP_TOKEN_INT_DEFAULT_SOUNDS_SET, + SETUP_TOKEN_INT_DEFAULT_MUSIC_SET, + SETUP_TOKEN_INT_FALLBACK_GRAPHICS_FILE, + SETUP_TOKEN_INT_FALLBACK_SOUNDS_FILE, + SETUP_TOKEN_INT_FALLBACK_MUSIC_FILE, + SETUP_TOKEN_INT_DEFAULT_LEVEL_SERIES, + SETUP_TOKEN_INT_CHOOSE_FROM_TOP_LEVELDIR, + SETUP_TOKEN_INT_SHOW_SCALING_IN_TITLE, + SETUP_TOKEN_INT_DEFAULT_WINDOW_WIDTH, + SETUP_TOKEN_INT_DEFAULT_WINDOW_HEIGHT, + + NUM_INTERNAL_SETUP_TOKENS +}; /* debug setup */ -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_0 0 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_1 1 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_2 2 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_3 3 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_4 4 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_5 5 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_6 6 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_7 7 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_8 8 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_9 9 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_0 10 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_1 11 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_2 12 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_3 13 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_4 14 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_5 15 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_6 16 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_7 17 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_8 18 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_9 19 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_USE_MOD_KEY 20 -#define SETUP_TOKEN_DEBUG_FRAME_DELAY_GAME_ONLY 21 -#define SETUP_TOKEN_DEBUG_SHOW_FRAMES_PER_SECOND 22 - -#define NUM_DEBUG_SETUP_TOKENS 23 +enum +{ + SETUP_TOKEN_DEBUG_FRAME_DELAY_0 = 0, + SETUP_TOKEN_DEBUG_FRAME_DELAY_1, + SETUP_TOKEN_DEBUG_FRAME_DELAY_2, + SETUP_TOKEN_DEBUG_FRAME_DELAY_3, + SETUP_TOKEN_DEBUG_FRAME_DELAY_4, + SETUP_TOKEN_DEBUG_FRAME_DELAY_5, + SETUP_TOKEN_DEBUG_FRAME_DELAY_6, + SETUP_TOKEN_DEBUG_FRAME_DELAY_7, + SETUP_TOKEN_DEBUG_FRAME_DELAY_8, + SETUP_TOKEN_DEBUG_FRAME_DELAY_9, + SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_0, + SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_1, + SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_2, + SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_3, + SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_4, + SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_5, + SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_6, + SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_7, + SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_8, + SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_9, + SETUP_TOKEN_DEBUG_FRAME_DELAY_USE_MOD_KEY, + SETUP_TOKEN_DEBUG_FRAME_DELAY_GAME_ONLY, + SETUP_TOKEN_DEBUG_SHOW_FRAMES_PER_SECOND, + + NUM_DEBUG_SETUP_TOKENS +}; /* options setup */ -#define SETUP_TOKEN_OPTIONS_VERBOSE 0 +enum +{ + SETUP_TOKEN_OPTIONS_VERBOSE = 0, -#define NUM_OPTIONS_SETUP_TOKENS 1 + NUM_OPTIONS_SETUP_TOKENS +}; static struct SetupInfo si; +static struct SetupAutoSetupInfo sasi; static struct SetupEditorInfo sei; static struct SetupEditorCascadeInfo seci; static struct SetupShortcutInfo ssi; @@ -8186,16 +8600,21 @@ static struct TokenInfo global_setup_tokens[] = { TYPE_SWITCH, &si.handicap, "handicap" }, { TYPE_SWITCH, &si.skip_levels, "skip_levels" }, { TYPE_SWITCH, &si.increment_levels, "increment_levels" }, + { TYPE_SWITCH, &si.auto_play_next_level, "auto_play_next_level" }, + { TYPE_SWITCH, &si.skip_scores_after_game, "skip_scores_after_game" }, { TYPE_SWITCH, &si.time_limit, "time_limit" }, { TYPE_SWITCH, &si.fullscreen, "fullscreen" }, { TYPE_INTEGER,&si.window_scaling_percent, "window_scaling_percent" }, { TYPE_STRING, &si.window_scaling_quality, "window_scaling_quality" }, { TYPE_STRING, &si.screen_rendering_mode, "screen_rendering_mode" }, + { TYPE_STRING, &si.vsync_mode, "vsync_mode" }, { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" }, { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor" }, + { TYPE_SWITCH, &si.ask_on_game_over, "ask_on_game_over" }, { 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_SWITCH, &si.game_speed_extended, "game_speed_extended" }, { TYPE_INTEGER,&si.game_frame_delay, "game_frame_delay" }, { TYPE_SWITCH, &si.sp_show_border_elements, "sp_show_border_elements" }, { TYPE_SWITCH, &si.small_game_graphics, "small_game_graphics" }, @@ -8209,9 +8628,24 @@ static struct TokenInfo global_setup_tokens[] = { TYPE_INTEGER,&si.volume_simple, "volume_simple" }, { TYPE_INTEGER,&si.volume_loops, "volume_loops" }, { TYPE_INTEGER,&si.volume_music, "volume_music" }, + { TYPE_SWITCH, &si.network_mode, "network_mode" }, + { TYPE_PLAYER, &si.network_player_nr, "network_player" }, + { TYPE_STRING, &si.network_server_hostname, "network_server_hostname" }, { TYPE_STRING, &si.touch.control_type, "touch.control_type" }, { TYPE_INTEGER,&si.touch.move_distance, "touch.move_distance" }, { TYPE_INTEGER,&si.touch.drop_distance, "touch.drop_distance" }, + { TYPE_INTEGER,&si.touch.transparency, "touch.transparency" }, + { TYPE_INTEGER,&si.touch.draw_outlined, "touch.draw_outlined" }, + { TYPE_INTEGER,&si.touch.draw_pressed, "touch.draw_pressed" }, + { TYPE_INTEGER,&si.touch.grid_xsize[0], "touch.virtual_buttons.0.xsize" }, + { TYPE_INTEGER,&si.touch.grid_ysize[0], "touch.virtual_buttons.0.ysize" }, + { TYPE_INTEGER,&si.touch.grid_xsize[1], "touch.virtual_buttons.1.xsize" }, + { TYPE_INTEGER,&si.touch.grid_ysize[1], "touch.virtual_buttons.1.ysize" }, +}; + +static struct TokenInfo auto_setup_tokens[] = +{ + { TYPE_INTEGER,&sasi.editor_zoom_tilesize, "editor.zoom_tilesize" }, }; static struct TokenInfo editor_setup_tokens[] = @@ -8234,6 +8668,8 @@ static struct TokenInfo editor_cascade_setup_tokens[] = { 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_mm, "editor.cascade.el_mm" }, + { TYPE_SWITCH, &seci.el_df, "editor.cascade.el_df" }, { TYPE_SWITCH, &seci.el_chars, "editor.cascade.el_chars" }, { TYPE_SWITCH, &seci.el_steel_chars, "editor.cascade.el_steel_chars" }, { TYPE_SWITCH, &seci.el_ce, "editor.cascade.el_ce" }, @@ -8388,16 +8824,21 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->handicap = TRUE; si->skip_levels = TRUE; si->increment_levels = TRUE; + si->auto_play_next_level = TRUE; + si->skip_scores_after_game = FALSE; si->time_limit = TRUE; si->fullscreen = FALSE; si->window_scaling_percent = STD_WINDOW_SCALING_PERCENT; si->window_scaling_quality = getStringCopy(SCALING_QUALITY_DEFAULT); si->screen_rendering_mode = getStringCopy(STR_SPECIAL_RENDERING_DEFAULT); + si->vsync_mode = getStringCopy(STR_VSYNC_MODE_DEFAULT); si->ask_on_escape = TRUE; si->ask_on_escape_editor = TRUE; + si->ask_on_game_over = TRUE; si->quick_switch = FALSE; si->input_on_focus = FALSE; si->prefer_aga_graphics = TRUE; + si->game_speed_extended = FALSE; si->game_frame_delay = GAME_FRAME_DELAY; si->sp_show_border_elements = FALSE; si->small_game_graphics = FALSE; @@ -8415,9 +8856,65 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->volume_loops = 100; /* percent */ si->volume_music = 100; /* percent */ + si->network_mode = FALSE; + si->network_player_nr = 0; /* first player */ + si->network_server_hostname = getStringCopy(STR_NETWORK_AUTO_DETECT); + si->touch.control_type = getStringCopy(TOUCH_CONTROL_DEFAULT); si->touch.move_distance = TOUCH_MOVE_DISTANCE_DEFAULT; /* percent */ si->touch.drop_distance = TOUCH_DROP_DISTANCE_DEFAULT; /* percent */ + si->touch.transparency = TOUCH_TRANSPARENCY_DEFAULT; /* percent */ + si->touch.draw_outlined = TRUE; + si->touch.draw_pressed = TRUE; + + for (i = 0; i < 2; i++) + { + char *default_grid_button[6][2] = + { + { " ", " ^^ " }, + { " ", " ^^ " }, + { " ", "<< >>" }, + { " ", "<< >>" }, + { "111222", " vv " }, + { "111222", " vv " } + }; + int grid_xsize = DEFAULT_GRID_XSIZE(i); + int grid_ysize = DEFAULT_GRID_YSIZE(i); + int min_xsize = MIN(6, grid_xsize); + int min_ysize = MIN(6, grid_ysize); + int startx = grid_xsize - min_xsize; + int starty = grid_ysize - min_ysize; + int x, y; + + // virtual buttons grid can only be set to defaults if video is initialized + // (this will be repeated if virtual buttons are not loaded from setup file) + if (video.initialized) + { + si->touch.grid_xsize[i] = grid_xsize; + si->touch.grid_ysize[i] = grid_ysize; + } + else + { + si->touch.grid_xsize[i] = -1; + si->touch.grid_ysize[i] = -1; + } + + for (x = 0; x < MAX_GRID_XSIZE; x++) + for (y = 0; y < MAX_GRID_YSIZE; y++) + si->touch.grid_button[i][x][y] = CHAR_GRID_BUTTON_NONE; + + for (x = 0; x < min_xsize; x++) + for (y = 0; y < min_ysize; y++) + si->touch.grid_button[i][x][starty + y] = + default_grid_button[y][0][x]; + + for (x = 0; x < min_xsize; x++) + for (y = 0; y < min_ysize; y++) + si->touch.grid_button[i][startx + x][starty + y] = + default_grid_button[y][1][x]; + } + + si->touch.grid_initialized = video.initialized; si->editor.el_boulderdash = TRUE; si->editor.el_emerald_mine = TRUE; @@ -8427,6 +8924,10 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->editor.el_supaplex = TRUE; si->editor.el_diamond_caves = TRUE; si->editor.el_dx_boulderdash = TRUE; + + si->editor.el_mirror_magic = TRUE; + si->editor.el_deflektor = TRUE; + si->editor.el_chars = TRUE; si->editor.el_steel_chars = TRUE; @@ -8551,6 +9052,11 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) #endif } +static void setSetupInfoToDefaults_AutoSetup(struct SetupInfo *si) +{ + si->auto_setup.editor_zoom_tilesize = MINI_TILESIZE; +} + static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si) { si->editor_cascade.el_bd = TRUE; @@ -8562,6 +9068,9 @@ static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si) si->editor_cascade.el_dc = TRUE; si->editor_cascade.el_dx = TRUE; + si->editor_cascade.el_mm = TRUE; + si->editor_cascade.el_df = TRUE; + si->editor_cascade.el_chars = FALSE; si->editor_cascade.el_steel_chars = FALSE; si->editor_cascade.el_ce = FALSE; @@ -8583,17 +9092,22 @@ static char *getHideSetupToken(void *setup_value) return hide_setup_token; } -static void setHideSetupEntry(void *setup_value_raw) +void setHideSetupEntry(void *setup_value) { - /* !!! DIRTY WORKAROUND; TO BE FIXED AFTER THE MM ENGINE RELEASE !!! */ - void *setup_value = setup_value_raw - (void *)&si + (void *)&setup; - char *hide_setup_token = getHideSetupToken(setup_value); if (setup_value != NULL) setHashEntry(hide_setup_hash, hide_setup_token, ""); } +static void setHideSetupEntryRaw(char *token_text, void *setup_value_raw) +{ + /* !!! DIRTY WORKAROUND; TO BE FIXED AFTER THE MM ENGINE RELEASE !!! */ + void *setup_value = setup_value_raw - (void *)&si + (void *)&setup; + + setHideSetupEntry(setup_value); +} + boolean hideSetupEntry(void *setup_value) { char *hide_setup_token = getHideSetupToken(setup_value); @@ -8614,7 +9128,7 @@ static void setSetupInfoFromTokenText(SetupFileHash *setup_file_hash, /* 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); + setHideSetupEntryRaw(token_text, token_info[token_nr].value); } static void setSetupInfoFromTokenInfo(SetupFileHash *setup_file_hash, @@ -8641,6 +9155,45 @@ static void decodeSetupFileHash(SetupFileHash *setup_file_hash) setSetupInfoFromTokenInfo(setup_file_hash, global_setup_tokens, i); setup = si; + /* virtual buttons setup */ + setup.touch.grid_initialized = TRUE; + for (i = 0; i < 2; i++) + { + int grid_xsize = setup.touch.grid_xsize[i]; + int grid_ysize = setup.touch.grid_ysize[i]; + int x, y; + + // if virtual buttons are not loaded from setup file, repeat initializing + // virtual buttons grid with default values later when video is initialized + if (grid_xsize == -1 || + grid_ysize == -1) + { + setup.touch.grid_initialized = FALSE; + + continue; + } + + for (y = 0; y < grid_ysize; y++) + { + char token_string[MAX_LINE_LEN]; + + sprintf(token_string, "touch.virtual_buttons.%d.%02d", i, y); + + char *value_string = getHashEntry(setup_file_hash, token_string); + + if (value_string == NULL) + continue; + + for (x = 0; x < grid_xsize; x++) + { + char c = value_string[x]; + + setup.touch.grid_button[i][x][y] = + (c == '.' ? CHAR_GRID_BUTTON_NONE : c); + } + } + } + /* editor setup */ sei = setup.editor; for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++) @@ -8695,6 +9248,24 @@ static void decodeSetupFileHash(SetupFileHash *setup_file_hash) for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++) setSetupInfoFromTokenInfo(setup_file_hash, options_setup_tokens, i); setup.options = soi; + + setHideRelatedSetupEntries(); +} + +static void decodeSetupFileHash_AutoSetup(SetupFileHash *setup_file_hash) +{ + int i; + + if (!setup_file_hash) + return; + + /* auto setup */ + sasi = setup.auto_setup; + for (i = 0; i < NUM_AUTO_SETUP_TOKENS; i++) + setSetupInfo(auto_setup_tokens, i, + getHashEntry(setup_file_hash, + auto_setup_tokens[i].text)); + setup.auto_setup = sasi; } static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash) @@ -8729,7 +9300,7 @@ void LoadSetupFromFilename(char *filename) } } -static void LoadSetup_SpecialPostProcessing() +static void LoadSetup_SpecialPostProcessing(void) { char *player_name_new; @@ -8750,7 +9321,7 @@ static void LoadSetup_SpecialPostProcessing() MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY); } -void LoadSetup() +void LoadSetup(void) { char *filename; @@ -8771,7 +9342,27 @@ void LoadSetup() LoadSetup_SpecialPostProcessing(); } -void LoadSetup_EditorCascade() +void LoadSetup_AutoSetup(void) +{ + char *filename = getPath2(getSetupDir(), AUTOSETUP_FILENAME); + SetupFileHash *setup_file_hash = NULL; + + /* always start with reliable default values */ + setSetupInfoToDefaults_AutoSetup(&setup); + + setup_file_hash = loadSetupFileHash(filename); + + if (setup_file_hash) + { + decodeSetupFileHash_AutoSetup(setup_file_hash); + + freeSetupFileHash(setup_file_hash); + } + + free(filename); +} + +void LoadSetup_EditorCascade(void) { char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME); SetupFileHash *setup_file_hash = NULL; @@ -8840,7 +9431,7 @@ static void LoadSetup_ReadGameControllerMappings(SetupFileHash *mappings_hash, fclose(file); } -void SaveSetup() +void SaveSetup(void) { char *filename = getSetupFilename(); FILE *file; @@ -8864,12 +9455,44 @@ void SaveSetup() if (i == SETUP_TOKEN_PLAYER_NAME + 1 || i == SETUP_TOKEN_GRAPHICS_SET || i == SETUP_TOKEN_VOLUME_SIMPLE || - i == SETUP_TOKEN_TOUCH_CONTROL_TYPE) + i == SETUP_TOKEN_NETWORK_MODE || + i == SETUP_TOKEN_TOUCH_CONTROL_TYPE || + i == SETUP_TOKEN_TOUCH_GRID_XSIZE_0 || + i == SETUP_TOKEN_TOUCH_GRID_XSIZE_1) fprintf(file, "\n"); fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i)); } + /* virtual buttons setup */ + for (i = 0; i < 2; i++) + { + int grid_xsize = setup.touch.grid_xsize[i]; + int grid_ysize = setup.touch.grid_ysize[i]; + int x, y; + + fprintf(file, "\n"); + + for (y = 0; y < grid_ysize; y++) + { + char token_string[MAX_LINE_LEN]; + char value_string[MAX_LINE_LEN]; + + sprintf(token_string, "touch.virtual_buttons.%d.%02d", i, y); + + for (x = 0; x < grid_xsize; x++) + { + char c = setup.touch.grid_button[i][x][y]; + + value_string[x] = (c == CHAR_GRID_BUTTON_NONE ? '.' : c); + } + + value_string[grid_xsize] = '\0'; + + fprintf(file, "%s\n", getFormattedSetupEntry(token_string, value_string)); + } + } + /* editor setup */ sei = setup.editor; fprintf(file, "\n"); @@ -8921,7 +9544,35 @@ void SaveSetup() SetFilePermissions(filename, PERMS_PRIVATE); } -void SaveSetup_EditorCascade() +void SaveSetup_AutoSetup(void) +{ + char *filename = getPath2(getSetupDir(), AUTOSETUP_FILENAME); + FILE *file; + int i; + + InitUserDataDirectory(); + + if (!(file = fopen(filename, MODE_WRITE))) + { + Error(ERR_WARN, "cannot write auto setup file '%s'", filename); + free(filename); + return; + } + + fprintFileHeader(file, AUTOSETUP_FILENAME); + + sasi = setup.auto_setup; + for (i = 0; i < NUM_AUTO_SETUP_TOKENS; i++) + fprintf(file, "%s\n", getSetupLine(auto_setup_tokens, "", i)); + + fclose(file); + + SetFilePermissions(filename, PERMS_PRIVATE); + + free(filename); +} + +void SaveSetup_EditorCascade(void) { char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME); FILE *file; @@ -8990,7 +9641,7 @@ void SaveSetup_AddGameControllerMapping(char *mapping) free(filename); } -void LoadCustomElementDescriptions() +void LoadCustomElementDescriptions(void) { char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS); SetupFileHash *setup_file_hash; @@ -9052,7 +9703,7 @@ static int get_token_parameter_value(char *token, char *value_raw) return get_parameter_value(value_raw, suffix, TYPE_INTEGER); } -void InitMenuDesignSettings_Static() +void InitMenuDesignSettings_Static(void) { int i; @@ -9067,7 +9718,7 @@ void InitMenuDesignSettings_Static() } } -static void InitMenuDesignSettings_SpecialPreProcessing() +static void InitMenuDesignSettings_SpecialPreProcessing(void) { int i; @@ -9159,7 +9810,7 @@ static void InitMenuDesignSettings_SpecialPreProcessing() } } -static void InitMenuDesignSettings_SpecialPostProcessing() +static void InitMenuDesignSettings_SpecialPostProcessing(void) { static struct { @@ -9188,7 +9839,7 @@ static void InitMenuDesignSettings_SpecialPostProcessing() *game_buttons_xy[i].dst = *game_buttons_xy[i].src; } -static void InitMenuDesignSettings_SpecialPostProcessing_AfterGraphics() +static void InitMenuDesignSettings_SpecialPostProcessing_AfterGraphics(void) { static struct { @@ -9382,6 +10033,40 @@ static void LoadMenuDesignSettingsFromFilename(char *filename) menu.draw_yoffset_setup[i] = get_integer_from_string(value_2); } + /* special case: initialize with default values that may be overwritten */ + /* (eg, init "menu.line_spacing.INFO[XXX]" from "menu.line_spacing.INFO") */ + for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++) + { + char *value_1 = getHashEntry(setup_file_hash,"menu.left_spacing.INFO"); + char *value_2 = getHashEntry(setup_file_hash,"menu.right_spacing.INFO"); + char *value_3 = getHashEntry(setup_file_hash,"menu.top_spacing.INFO"); + char *value_4 = getHashEntry(setup_file_hash,"menu.bottom_spacing.INFO"); + char *value_5 = getHashEntry(setup_file_hash,"menu.paragraph_spacing.INFO"); + char *value_6 = getHashEntry(setup_file_hash,"menu.headline1_spacing.INFO"); + char *value_7 = getHashEntry(setup_file_hash,"menu.headline2_spacing.INFO"); + char *value_8 = getHashEntry(setup_file_hash,"menu.line_spacing.INFO"); + char *value_9 = getHashEntry(setup_file_hash,"menu.extra_spacing.INFO"); + + if (value_1 != NULL) + menu.left_spacing_info[i] = get_integer_from_string(value_1); + if (value_2 != NULL) + menu.right_spacing_info[i] = get_integer_from_string(value_2); + if (value_3 != NULL) + menu.top_spacing_info[i] = get_integer_from_string(value_3); + if (value_4 != NULL) + menu.bottom_spacing_info[i] = get_integer_from_string(value_4); + if (value_5 != NULL) + menu.paragraph_spacing_info[i] = get_integer_from_string(value_5); + if (value_6 != NULL) + menu.headline1_spacing_info[i] = get_integer_from_string(value_6); + if (value_7 != NULL) + menu.headline2_spacing_info[i] = get_integer_from_string(value_7); + if (value_8 != NULL) + menu.line_spacing_info[i] = get_integer_from_string(value_8); + if (value_9 != NULL) + menu.extra_spacing_info[i] = get_integer_from_string(value_9); + } + /* special case: initialize with default values that may be overwritten */ /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) @@ -9588,7 +10273,7 @@ static void LoadMenuDesignSettingsFromFilename(char *filename) freeSetupFileHash(setup_file_hash); } -void LoadMenuDesignSettings() +void LoadMenuDesignSettings(void) { char *filename_base = UNDEFINED_FILENAME, *filename_local; @@ -9612,7 +10297,7 @@ void LoadMenuDesignSettings() InitMenuDesignSettings_SpecialPostProcessing(); } -void LoadMenuDesignSettings_AfterGraphics() +void LoadMenuDesignSettings_AfterGraphics(void) { InitMenuDesignSettings_SpecialPostProcessing_AfterGraphics(); } @@ -9814,7 +10499,7 @@ static boolean sound_info_listed(struct MusicFileInfo *list, char *basename) return music_info_listed_ext(list, basename, TRUE); } -void LoadMusicInfo() +void LoadMusicInfo(void) { char *music_directory = getCustomMusicDirectory(); int num_music = getMusicListSize(); @@ -9941,8 +10626,8 @@ void LoadMusicInfo() } } -void add_helpanim_entry(int element, int action, int direction, int delay, - int *num_list_entries) +static void add_helpanim_entry(int element, int action, int direction, + int delay, int *num_list_entries) { struct HelpAnimInfo *new_list_entry; (*num_list_entries)++; @@ -9958,7 +10643,7 @@ void add_helpanim_entry(int element, int action, int direction, int delay, new_list_entry->delay = delay; } -void print_unknown_token(char *filename, char *token, int token_nr) +static void print_unknown_token(char *filename, char *token, int token_nr) { if (token_nr == 0) { @@ -9970,13 +10655,13 @@ void print_unknown_token(char *filename, char *token, int token_nr) Error(ERR_INFO, "- token: '%s'", token); } -void print_unknown_token_end(int token_nr) +static void print_unknown_token_end(int token_nr) { if (token_nr > 0) Error(ERR_INFO_LINE, "-"); } -void LoadHelpAnimInfo() +void LoadHelpAnimInfo(void) { char *filename = getHelpAnimFilename(); SetupFileList *setup_file_list = NULL, *list; @@ -10186,7 +10871,7 @@ void LoadHelpAnimInfo() #endif } -void LoadHelpTextInfo() +void LoadHelpTextInfo(void) { char *filename = getHelpTextFilename(); int i; @@ -10228,7 +10913,7 @@ void LoadHelpTextInfo() #define MAX_NUM_CONVERT_LEVELS 1000 -void ConvertLevels() +void ConvertLevels(void) { static LevelDirTree *convert_leveldir = NULL; static int convert_level_nr = -1; @@ -10340,7 +11025,7 @@ void ConvertLevels() /* create and save images for use in level sketches (raw BMP format) */ /* ------------------------------------------------------------------------- */ -void CreateLevelSketchImages() +void CreateLevelSketchImages(void) { #if defined(TARGET_SDL) Bitmap *bitmap1;