@@ -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 file
(can be either a savegame, scenario, or heightmap) at start or start a new game if omitted.
must be either an absolute path or one relative to the current path or one of
the search paths.
.It Fl G Ar seed
@@ -447,9 +447,6 @@ std::tuple<FiosType, std::string> FiosGe
* .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(SaveLoadOperati
* @see FiosGetFileList
* @see FiosGetScenarioList
*/
static std::tuple<FiosType, std::string> FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext)
std::tuple<FiosType, std::string> 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(SaveLoadOperati
FiosGetFileList(fop, &FiosGetScenarioListCallback, subdir, file_list);
static std::tuple<FiosType, std::string> FiosGetHeightmapListCallback(SaveLoadOperation, const std::string &file, const std::string_view ext)
std::tuple<FiosType, std::string> FiosGetHeightmapListCallback(SaveLoadOperation, const std::string &file, const std::string_view ext)
/* Show heightmap files
* .PNG PNG Based heightmap files
@@ -117,6 +117,8 @@ std::string FiosMakeHeightmapName(const
std::string FiosMakeSavegameName(const char *name);
std::tuple<FiosType, std::string> FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext);
std::tuple<FiosType, std::string> FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext);
std::tuple<FiosType, std::string> FiosGetHeightmapListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext);
void ScanScenarios();
const char *FindScenario(const ContentInfo *ci, bool md5sum);
@@ -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. */
@@ -520,14 +520,14 @@ bool GetHeightmapDimensions(DetailedFile
* @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,
FixSlopes();
MarkWholeScreenDirty();
return true;
/**
@@ -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();
@@ -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())) {
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();
void OnTick_Town();
@@ -139,6 +139,6 @@ void DoClearSquare(TileIndex tile);
void RunTileLoop();
void InitializeLandscape();
void GenerateLandscape(byte mode);
bool GenerateLandscape(byte mode);
#endif /* LANDSCAPE_H */
@@ -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;
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);
std::tie(ft, _) = FiosGetHeightmapListCallback(SLO_LOAD, _file_to_saveload.name, extension);
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;
_file_to_saveload.SetMode(SLO_LOAD, GetAbstractFileType(ft), GetDetailedFileType(ft));
@@ -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();
@@ -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);
Status change: