diff --git a/docs/openttd.6 b/docs/openttd.6 index c1cbd88791..0319f98cc8 100644 --- a/docs/openttd.6 +++ b/docs/openttd.6 @@ -13,7 +13,7 @@ .Op Fl c Ar config_file .Op Fl d Op Ar level | Ar cat Ns = Ns Ar lvl Ns Op , Ns Ar ... .Op Fl D Oo Ar host Oc Ns Op : Ns Ar port -.Op Fl g Op Ar savegame +.Op Fl g Op Ar file .Op Fl G Ar seed .Op Fl I Ar graphicsset .Op Fl m Ar driver @@ -62,11 +62,11 @@ Start in world editor mode. .It Fl f Fork into background (dedicated server only, see .Fl D ) . -.It Fl g Op Ar savegame +.It Fl g Op Ar file Load -.Ar savegame -at start or start a new game if omitted. -.Ar savegame +.Ar file +(can be either a savegame, scenario, or heightmap) at start or start a new game if omitted. +.Ar file must be either an absolute path or one relative to the current path or one of the search paths. .It Fl G Ar seed diff --git a/src/fios.cpp b/src/fios.cpp index 3b7efd822e..48e0466eea 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -447,9 +447,6 @@ std::tuple FiosGetSavegameListCallback(SaveLoadOperation * .SV1 Transport Tycoon Deluxe (Patch) saved game * .SV2 Transport Tycoon Deluxe (Patch) saved 2-player game */ - /* Don't crash if we supply no extension */ - if (ext.empty()) return { FIOS_TYPE_INVALID, {} }; - if (StrEqualsIgnoreCase(ext, ".sav")) { return { FIOS_TYPE_FILE, GetFileTitle(file, SAVE_DIR) }; } @@ -490,7 +487,7 @@ void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list) * @see FiosGetFileList * @see FiosGetScenarioList */ -static std::tuple FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext) +std::tuple FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext) { /* Show scenario files * .SCN OpenTTD style scenario file @@ -530,7 +527,7 @@ void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list) FiosGetFileList(fop, &FiosGetScenarioListCallback, subdir, file_list); } -static std::tuple FiosGetHeightmapListCallback(SaveLoadOperation, const std::string &file, const std::string_view ext) +std::tuple FiosGetHeightmapListCallback(SaveLoadOperation, const std::string &file, const std::string_view ext) { /* Show heightmap files * .PNG PNG Based heightmap files diff --git a/src/fios.h b/src/fios.h index 8c727c2e32..5827538e46 100644 --- a/src/fios.h +++ b/src/fios.h @@ -117,6 +117,8 @@ std::string FiosMakeHeightmapName(const char *name); std::string FiosMakeSavegameName(const char *name); std::tuple FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext); +std::tuple FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext); +std::tuple FiosGetHeightmapListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext); void ScanScenarios(); const char *FindScenario(const ContentInfo *ci, bool md5sum); diff --git a/src/genworld.cpp b/src/genworld.cpp index 762cc9a69e..c5d5f10df8 100644 --- a/src/genworld.cpp +++ b/src/genworld.cpp @@ -103,8 +103,14 @@ static void _GenerateWorld() /* Must start economy early because of the costs. */ StartupEconomy(); + bool landscape_generated = false; + /* Don't generate landscape items when in the scenario editor. */ - if (_gw.mode == GWM_EMPTY) { + if (_gw.mode != GWM_EMPTY) { + landscape_generated = GenerateLandscape(_gw.mode); + } + + if (!landscape_generated) { SetGeneratingWorldProgress(GWP_OBJECT, 1); /* Make sure the tiles at the north border are void tiles if needed. */ @@ -121,7 +127,6 @@ static void _GenerateWorld() _settings_game.game_creation.snow_line_height = DEF_SNOWLINE_HEIGHT; } else { - GenerateLandscape(_gw.mode); GenerateClearTile(); /* Only generate towns, tree and industries in newgame mode. */ diff --git a/src/heightmap.cpp b/src/heightmap.cpp index 7352ceaabb..230a090bad 100644 --- a/src/heightmap.cpp +++ b/src/heightmap.cpp @@ -520,14 +520,14 @@ bool GetHeightmapDimensions(DetailedFileType dft, const char *filename, uint *x, * @param dft Type of image file. * @param filename of the heightmap file to be imported */ -void LoadHeightmap(DetailedFileType dft, const char *filename) +bool LoadHeightmap(DetailedFileType dft, const char *filename) { uint x, y; byte *map = nullptr; if (!ReadHeightMap(dft, filename, &x, &y, &map)) { free(map); - return; + return false; } GrayscaleToMapHeights(x, y, map); @@ -535,6 +535,8 @@ void LoadHeightmap(DetailedFileType dft, const char *filename) FixSlopes(); MarkWholeScreenDirty(); + + return true; } /** diff --git a/src/heightmap.h b/src/heightmap.h index 9c3e71bbee..d7c431c2e4 100644 --- a/src/heightmap.h +++ b/src/heightmap.h @@ -22,7 +22,7 @@ enum HeightmapRotation { }; bool GetHeightmapDimensions(DetailedFileType dft, const char *filename, uint *x, uint *y); -void LoadHeightmap(DetailedFileType dft, const char *filename); +bool LoadHeightmap(DetailedFileType dft, const char *filename); void FlatEmptyWorld(byte tile_height); void FixSlopes(); diff --git a/src/landscape.cpp b/src/landscape.cpp index 5437995a4d..9202253a1b 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -1557,7 +1557,7 @@ static uint8_t CalculateDesertLine() return CalculateCoverageLine(100 - _settings_game.game_creation.desert_coverage, 4); } -void GenerateLandscape(byte mode) +bool GenerateLandscape(byte mode) { /** Number of steps of landscape generation */ enum GenLandscapeSteps { @@ -1571,7 +1571,9 @@ void GenerateLandscape(byte mode) if (mode == GWM_HEIGHTMAP) { SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP); - LoadHeightmap(_file_to_saveload.detail_ftype, _file_to_saveload.name.c_str()); + if (!LoadHeightmap(_file_to_saveload.detail_ftype, _file_to_saveload.name.c_str())) { + return false; + } IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) { SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS); @@ -1657,6 +1659,7 @@ void GenerateLandscape(byte mode) } CreateRivers(); + return true; } void OnTick_Town(); diff --git a/src/landscape.h b/src/landscape.h index e6e00a8e43..249dcc9efa 100644 --- a/src/landscape.h +++ b/src/landscape.h @@ -139,6 +139,6 @@ void DoClearSquare(TileIndex tile); void RunTileLoop(); void InitializeLandscape(); -void GenerateLandscape(byte mode); +bool GenerateLandscape(byte mode); #endif /* LANDSCAPE_H */ diff --git a/src/openttd.cpp b/src/openttd.cpp index 58af9ba69f..9a6db6259d 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -165,7 +165,7 @@ static void ShowHelp() " -t year = Set starting year\n" " -d [[fac=]lvl[,...]]= Debug mode\n" " -e = Start Editor\n" - " -g [savegame] = Start new/save game immediately\n" + " -g [savegame|scenario|heightmap] = Start new/savegame/scenario/heightmap immediately\n" " -G seed = Set random seed\n" " -n host[:port][#company]= Join network game\n" " -p password = Password to join server\n" @@ -577,21 +577,37 @@ int openttd_main(int argc, char *argv[]) if (mgo.opt != nullptr) SetDebugString(mgo.opt, ShowInfoI); break; } - case 'e': _switch_mode = (_switch_mode == SM_LOAD_GAME || _switch_mode == SM_LOAD_SCENARIO ? SM_LOAD_SCENARIO : SM_EDITOR); break; + case 'e': + /* Allow for '-e' before or after '-g'. */ + switch (_switch_mode) { + case SM_MENU: _switch_mode = SM_EDITOR; break; + case SM_LOAD_GAME: _switch_mode = SM_LOAD_SCENARIO; break; + case SM_START_HEIGHTMAP: _switch_mode = SM_LOAD_HEIGHTMAP; break; + default: break; + } + break; case 'g': if (mgo.opt != nullptr) { _file_to_saveload.name = mgo.opt; - bool is_scenario = _switch_mode == SM_EDITOR || _switch_mode == SM_LOAD_SCENARIO; - _switch_mode = is_scenario ? SM_LOAD_SCENARIO : SM_LOAD_GAME; - _file_to_saveload.SetMode(SLO_LOAD, is_scenario ? FT_SCENARIO : FT_SAVEGAME, DFT_GAME_FILE); - - /* if the file doesn't exist or it is not a valid savegame, let the saveload code show an error */ - auto t = _file_to_saveload.name.find_last_of('.'); - if (t != std::string::npos) { - auto [ft, _] = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name, _file_to_saveload.name.substr(t)); - if (ft != FIOS_TYPE_INVALID) _file_to_saveload.SetMode(ft); + + std::string extension = std::filesystem::path(_file_to_saveload.name).extension().string(); + auto [ft, _] = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name, extension); + if (ft == FIOS_TYPE_INVALID) { + std::tie(ft, _) = FiosGetScenarioListCallback(SLO_LOAD, _file_to_saveload.name, extension); + } + if (ft == FIOS_TYPE_INVALID) { + std::tie(ft, _) = FiosGetHeightmapListCallback(SLO_LOAD, _file_to_saveload.name, extension); } + /* Allow for '-e' before or after '-g'. */ + switch (GetAbstractFileType(ft)) { + case FT_SAVEGAME: _switch_mode = (_switch_mode == SM_EDITOR ? SM_LOAD_SCENARIO : SM_LOAD_GAME); break; + case FT_SCENARIO: _switch_mode = (_switch_mode == SM_EDITOR ? SM_LOAD_SCENARIO : SM_LOAD_GAME); break; + case FT_HEIGHTMAP: _switch_mode = (_switch_mode == SM_EDITOR ? SM_LOAD_HEIGHTMAP : SM_START_HEIGHTMAP); break; + default: break; + } + + _file_to_saveload.SetMode(SLO_LOAD, GetAbstractFileType(ft), GetDetailedFileType(ft)); break; } @@ -1131,6 +1147,8 @@ void SwitchToMode(SwitchMode new_mode) case SM_LOAD_HEIGHTMAP: // Load heightmap from scenario editor SetLocalCompany(OWNER_NONE); + _game_mode = GM_EDITOR; + GenerateWorld(GWM_HEIGHTMAP, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y); GenerateSavegameId(); MarkWholeScreenDirty(); diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp index f891be2402..e2613f2313 100644 --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -204,8 +204,8 @@ void VideoDriver_Dedicated::MainLoop() _network_dedicated = true; _current_company = _local_company = COMPANY_SPECTATOR; - /* If SwitchMode is SM_LOAD_GAME, it means that the user used the '-g' options */ - if (_switch_mode != SM_LOAD_GAME) { + /* If SwitchMode is SM_LOAD_GAME / SM_START_HEIGHTMAP, it means that the user used the '-g' options */ + if (_switch_mode != SM_LOAD_GAME && _switch_mode != SM_START_HEIGHTMAP) { StartNewGameWithoutGUI(GENERATE_NEW_SEED); }