diff --git a/config.lib b/config.lib
index ab9bb82b61..961e5eae8c 100644
--- a/config.lib
+++ b/config.lib
@@ -1265,7 +1265,12 @@ make_compiler_cflags() {
# remark #2259: non-pointer conversion from ... to ... may lose significant bits
flags="$flags -wd2259"
# Use c++0x mode so static_assert() is available
- cxxflags="$cxxflags -std=c++0x"
+ cxxflags="$cxxflags -std=c++11"
+ fi
+
+ if [ $cc_version -lt 140 ]; then
+ log 1 "configure: error: ICC version is too old: `$1 -dumpversion`, minumum: 14.0"
+ exit 1
fi
if [ "$enable_lto" != "0" ]; then
@@ -1285,7 +1290,7 @@ make_compiler_cflags() {
# -W alone doesn't enable all warnings enabled by -Wall; on the other hand,
# -Weverything enables too many useless warnings that can't be disabled (as of 3.0)
- flags="$flags -Wall -W"
+ flags="$flags -Wall -W -Wextra"
# warning: unused parameter '...'
flags="$flags -Wno-unused-parameter"
@@ -1326,6 +1331,14 @@ make_compiler_cflags() {
flags="$flags -Wno-unused-variable"
fi
+ if [ "$cc_version" -ge "33" ]; then
+ # clang completed C++11 support in version 3.3
+ flags="$flags -std=c++11"
+ else
+ log 1 "configure: error: clang version is too old: `$1 -v 2>&1 | head -n 1`, minumum: 3.3"
+ exit 1
+ fi
+
# rdynamic is used to get useful stack traces from crash reports.
ldflags="$ldflags -rdynamic"
else
@@ -1385,7 +1398,7 @@ make_compiler_cflags() {
if [ $cc_version -ge 403 ] && [ $cc_version -lt 600 ]; then
# Use gnu++0x mode so static_assert() is available.
# Don't use c++0x, it breaks mingw (with gcc 4.4.0).
- cxxflags="$cxxflags -std=gnu++0x"
+ cxxflags="$cxxflags -std=gnu++11"
fi
if [ $cc_version -eq 405 ]; then
@@ -1401,6 +1414,9 @@ make_compiler_cflags() {
cxxflags="$cxxflags -Wno-narrowing"
# Disable bogus 'attempt to free a non-heap object' warning
flags="$flags -Wno-free-nonheap-object"
+ else
+ log 1 "configure: error: GCC version is too old: `$1 -dumpversion`, minumum: 4.7"
+ exit 1
fi
if [ $cc_version -ge 600 ]; then
diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj
index 99a66d683f..18a3cb23ba 100644
--- a/projects/openttd_vs100.vcxproj
+++ b/projects/openttd_vs100.vcxproj
@@ -571,6 +571,7 @@
+
diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters
index 0b6dc573b4..16848eb7b8 100644
--- a/projects/openttd_vs100.vcxproj.filters
+++ b/projects/openttd_vs100.vcxproj.filters
@@ -942,6 +942,9 @@
Header Files
+
+ Header Files
+
Header Files
diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj
index 68d2f1bf2c..5aa11e6f4a 100644
--- a/projects/openttd_vs140.vcxproj
+++ b/projects/openttd_vs140.vcxproj
@@ -588,6 +588,7 @@
+
diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters
index 0b6dc573b4..16848eb7b8 100644
--- a/projects/openttd_vs140.vcxproj.filters
+++ b/projects/openttd_vs140.vcxproj.filters
@@ -942,6 +942,9 @@
Header Files
+
+ Header Files
+
Header Files
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
index 361154db2b..9f4e2bbf3e 100644
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -1558,6 +1558,10 @@
RelativePath=".\..\src\safeguards.h"
>
+
+
diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj
index d27acf5db3..930522942c 100644
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -1555,6 +1555,10 @@
RelativePath=".\..\src\safeguards.h"
>
+
+
diff --git a/source.list b/source.list
index 62b1dd3f43..7824ff8e9d 100644
--- a/source.list
+++ b/source.list
@@ -310,6 +310,7 @@ road_type.h
roadstop_base.h
roadveh.h
safeguards.h
+scope.h
screenshot.h
sdl.h
sound/sdl_s.h
diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp
index 8d9e04113d..9cfc8e8f9d 100644
--- a/src/console_cmds.cpp
+++ b/src/console_cmds.cpp
@@ -45,6 +45,38 @@
/* scriptfile handling */
static bool _script_running; ///< Script is running (used to abort execution when #ConReturn is encountered).
+/** File list storage for the console, for caching the last 'ls' command. */
+class ConsoleFileList : public FileList {
+public:
+ ConsoleFileList() : FileList()
+ {
+ this->file_list_valid = false;
+ }
+
+ /** Declare the file storage cache as being invalid, also clears all stored files. */
+ void InvalidateFileList()
+ {
+ this->Clear();
+ this->file_list_valid = false;
+ }
+
+ /**
+ * (Re-)validate the file storage cache. Only makes a change if the storage was invalid, or if \a force_reload.
+ * @param Always reload the file storage cache.
+ */
+ void ValidateFileList(bool force_reload = false)
+ {
+ if (force_reload || !this->file_list_valid) {
+ this->BuildFileList(FT_SAVEGAME, SLO_LOAD);
+ this->file_list_valid = true;
+ }
+ }
+
+ bool file_list_valid; ///< If set, the file list is valid.
+};
+
+static ConsoleFileList _console_file_list; ///< File storage cache for the console.
+
/* console command defines */
#define DEF_CONSOLE_CMD(function) static bool function(byte argc, char *argv[])
#define DEF_CONSOLE_HOOK(function) static ConsoleHookResult function(bool echo)
@@ -286,7 +318,7 @@ DEF_CONSOLE_CMD(ConSave)
char *filename = str_fmt("%s.sav", argv[1]);
IConsolePrint(CC_DEFAULT, "Saving map...");
- if (SaveOrLoad(filename, SL_SAVE, SAVE_DIR) != SL_OK) {
+ if (SaveOrLoad(filename, SLO_SAVE, DFT_GAME_FILE, SAVE_DIR) != SL_OK) {
IConsolePrint(CC_ERROR, "Saving map failed");
} else {
IConsolePrintF(CC_DEFAULT, "Map successfully saved to %s", filename);
@@ -315,42 +347,6 @@ DEF_CONSOLE_CMD(ConSaveConfig)
return true;
}
-/**
- * Get savegame file informations.
- * @param file The savegame filename to return information about. Can be the actual name
- * or a numbered entry into the filename list.
- * @return FiosItem The information on the file.
- */
-static const FiosItem *GetFiosItem(const char *file)
-{
- _saveload_mode = SLD_LOAD_GAME;
- BuildFileList();
-
- for (const FiosItem *item = _fios_items.Begin(); item != _fios_items.End(); item++) {
- if (strcmp(file, item->name) == 0) return item;
- if (strcmp(file, item->title) == 0) return item;
- }
-
- /* If no name matches, try to parse it as number */
- char *endptr;
- int i = strtol(file, &endptr, 10);
- if (file == endptr || *endptr != '\0') i = -1;
-
- if (IsInsideMM(i, 0, _fios_items.Length())) return _fios_items.Get(i);
-
- /* As a last effort assume it is an OpenTTD savegame and
- * that the ".sav" part was not given. */
- char long_file[MAX_PATH];
- seprintf(long_file, lastof(long_file), "%s.sav", file);
- for (const FiosItem *item = _fios_items.Begin(); item != _fios_items.End(); item++) {
- if (strcmp(long_file, item->name) == 0) return item;
- if (strcmp(long_file, item->title) == 0) return item;
- }
-
- return NULL;
-}
-
-
DEF_CONSOLE_CMD(ConLoad)
{
if (argc == 0) {
@@ -361,24 +357,21 @@ DEF_CONSOLE_CMD(ConLoad)
if (argc != 2) return false;
const char *file = argv[1];
- const FiosItem *item = GetFiosItem(file);
+ _console_file_list.ValidateFileList();
+ const FiosItem *item = _console_file_list.FindItem(file);
if (item != NULL) {
- switch (item->type) {
- case FIOS_TYPE_FILE: case FIOS_TYPE_OLDFILE: {
- _switch_mode = SM_LOAD_GAME;
- SetFiosType(item->type);
-
- strecpy(_file_to_saveload.name, FiosBrowseTo(item), lastof(_file_to_saveload.name));
- strecpy(_file_to_saveload.title, item->title, lastof(_file_to_saveload.title));
- break;
- }
- default: IConsolePrintF(CC_ERROR, "%s: Not a savegame.", file);
+ if (GetAbstractFileType(item->type) == FT_SAVEGAME) {
+ _switch_mode = SM_LOAD_GAME;
+ _file_to_saveload.SetMode(item->type);
+ _file_to_saveload.SetName(FiosBrowseTo(item));
+ _file_to_saveload.SetTitle(item->title);
+ } else {
+ IConsolePrintF(CC_ERROR, "%s: Not a savegame.", file);
}
} else {
IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file);
}
- FiosFreeSavegameList();
return true;
}
@@ -393,7 +386,8 @@ DEF_CONSOLE_CMD(ConRemove)
if (argc != 2) return false;
const char *file = argv[1];
- const FiosItem *item = GetFiosItem(file);
+ _console_file_list.ValidateFileList();
+ const FiosItem *item = _console_file_list.FindItem(file);
if (item != NULL) {
if (!FiosDelete(item->name)) {
IConsolePrintF(CC_ERROR, "%s: Failed to delete file", file);
@@ -402,7 +396,7 @@ DEF_CONSOLE_CMD(ConRemove)
IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file);
}
- FiosFreeSavegameList();
+ _console_file_list.InvalidateFileList();
return true;
}
@@ -415,13 +409,11 @@ DEF_CONSOLE_CMD(ConListFiles)
return true;
}
- BuildFileList();
-
- for (uint i = 0; i < _fios_items.Length(); i++) {
- IConsolePrintF(CC_DEFAULT, "%d) %s", i, _fios_items[i].title);
+ _console_file_list.ValidateFileList(true);
+ for (uint i = 0; i < _console_file_list.Length(); i++) {
+ IConsolePrintF(CC_DEFAULT, "%d) %s", i, _console_file_list[i].title);
}
- FiosFreeSavegameList();
return true;
}
@@ -436,7 +428,8 @@ DEF_CONSOLE_CMD(ConChangeDirectory)
if (argc != 2) return false;
const char *file = argv[1];
- const FiosItem *item = GetFiosItem(file);
+ _console_file_list.ValidateFileList(true);
+ const FiosItem *item = _console_file_list.FindItem(file);
if (item != NULL) {
switch (item->type) {
case FIOS_TYPE_DIR: case FIOS_TYPE_DRIVE: case FIOS_TYPE_PARENT:
@@ -448,7 +441,7 @@ DEF_CONSOLE_CMD(ConChangeDirectory)
IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file);
}
- FiosFreeSavegameList();
+ _console_file_list.InvalidateFileList();
return true;
}
@@ -462,8 +455,8 @@ DEF_CONSOLE_CMD(ConPrintWorkingDirectory)
}
/* XXX - Workaround for broken file handling */
- FiosGetSavegameList(SLD_LOAD_GAME);
- FiosFreeSavegameList();
+ _console_file_list.ValidateFileList(true);
+ _console_file_list.InvalidateFileList();
FiosGetDescText(&path, NULL);
IConsolePrint(CC_DEFAULT, path);
diff --git a/src/core/smallvec_type.hpp b/src/core/smallvec_type.hpp
index 62de176a54..8676265d26 100644
--- a/src/core/smallvec_type.hpp
+++ b/src/core/smallvec_type.hpp
@@ -256,6 +256,8 @@ public:
/**
* Get the number of items in the list.
+ *
+ * @return The number of items in the list.
*/
inline uint Length() const
{
diff --git a/src/crashlog.cpp b/src/crashlog.cpp
index 4000cfb03e..53a85e442c 100644
--- a/src/crashlog.cpp
+++ b/src/crashlog.cpp
@@ -388,7 +388,7 @@ bool CrashLog::WriteSavegame(char *filename, const char *filename_last) const
seprintf(filename, filename_last, "%scrash.sav", _personal_dir);
/* Don't do a threaded saveload. */
- return SaveOrLoad(filename, SL_SAVE, NO_DIRECTORY, false) == SL_OK;
+ return SaveOrLoad(filename, SLO_SAVE, DFT_GAME_FILE, NO_DIRECTORY, false) == SL_OK;
} catch (...) {
return false;
}
diff --git a/src/fileio_type.h b/src/fileio_type.h
index 87cb2d1a82..fd3ac84554 100644
--- a/src/fileio_type.h
+++ b/src/fileio_type.h
@@ -14,6 +14,96 @@
#include "core/enum_type.hpp"
+/** The different abstract types of files that the system knows about. */
+enum AbstractFileType {
+ FT_NONE, ///< nothing to do
+ FT_SAVEGAME, ///< old or new savegame
+ FT_SCENARIO, ///< old or new scenario
+ FT_HEIGHTMAP, ///< heightmap file
+
+ FT_INVALID = 7, ///< Invalid or unknown file type.
+ FT_NUMBITS = 3, ///< Number of bits required for storing a #AbstractFileType value.
+ FT_MASK = (1 << FT_NUMBITS) - 1, ///< Bitmask for extracting an abstract file type.
+};
+
+/** Kinds of files in each #AbstractFileType. */
+enum DetailedFileType {
+ /* Save game and scenario files. */
+ DFT_OLD_GAME_FILE, ///< Old save game or scenario file.
+ DFT_GAME_FILE, ///< Save game or scenario file.
+
+ /* Heightmap files. */
+ DFT_HEIGHTMAP_BMP, ///< BMP file.
+ DFT_HEIGHTMAP_PNG, ///< PNG file.
+
+ /* fios 'files' */
+ DFT_FIOS_DRIVE, ///< A drive (letter) entry.
+ DFT_FIOS_PARENT, ///< A parent directory entry.
+ DFT_FIOS_DIR, ///< A directory entry.
+ DFT_FIOS_DIRECT, ///< Direct filename.
+
+ DFT_INVALID = 255, ///< Unknown or invalid file.
+};
+
+/** Operation performed on the file. */
+enum SaveLoadOperation {
+ SLO_CHECK, ///< Load file for checking and/or preview.
+ SLO_LOAD, ///< File is being loaded.
+ SLO_SAVE, ///< File is being saved.
+
+ SLO_INVALID, ///< Unknown file operation.
+};
+
+/**
+ * Construct an enum value for #FiosType as a combination of an abstract and a detailed file type.
+ * @param abstract Abstract file type (one of #AbstractFileType).
+ * @param detailed Detailed file type (one of #DetailedFileType).
+ */
+#define MAKE_FIOS_TYPE(abstract, detailed) ((abstract) | ((detailed) << FT_NUMBITS))
+
+/**
+ * Elements of a file system that are recognized.
+ * Values are a combination of #AbstractFileType and #DetailedFileType.
+ * @see GetAbstractFileType GetDetailedFileType
+ */
+enum FiosType {
+ FIOS_TYPE_DRIVE = MAKE_FIOS_TYPE(FT_NONE, DFT_FIOS_DRIVE),
+ FIOS_TYPE_PARENT = MAKE_FIOS_TYPE(FT_NONE, DFT_FIOS_PARENT),
+ FIOS_TYPE_DIR = MAKE_FIOS_TYPE(FT_NONE, DFT_FIOS_DIR),
+ FIOS_TYPE_DIRECT = MAKE_FIOS_TYPE(FT_NONE, DFT_FIOS_DIRECT),
+
+ FIOS_TYPE_FILE = MAKE_FIOS_TYPE(FT_SAVEGAME, DFT_GAME_FILE),
+ FIOS_TYPE_OLDFILE = MAKE_FIOS_TYPE(FT_SAVEGAME, DFT_OLD_GAME_FILE),
+ FIOS_TYPE_SCENARIO = MAKE_FIOS_TYPE(FT_SCENARIO, DFT_GAME_FILE),
+ FIOS_TYPE_OLD_SCENARIO = MAKE_FIOS_TYPE(FT_SCENARIO, DFT_OLD_GAME_FILE),
+ FIOS_TYPE_PNG = MAKE_FIOS_TYPE(FT_HEIGHTMAP, DFT_HEIGHTMAP_PNG),
+ FIOS_TYPE_BMP = MAKE_FIOS_TYPE(FT_HEIGHTMAP, DFT_HEIGHTMAP_BMP),
+
+ FIOS_TYPE_INVALID = MAKE_FIOS_TYPE(FT_INVALID, DFT_INVALID),
+};
+
+#undef MAKE_FIOS_TYPE
+
+/**
+ * Extract the abstract file type from a #FiosType.
+ * @param fios_type Type to query.
+ * @return The Abstract file type of the \a fios_type.
+ */
+inline AbstractFileType GetAbstractFileType(FiosType fios_type)
+{
+ return static_cast(fios_type & FT_MASK);
+}
+
+/**
+ * Extract the detailed file type from a #FiosType.
+ * @param fios_type Type to query.
+ * @return The Detailed file type of the \a fios_type.
+ */
+inline DetailedFileType GetDetailedFileType(FiosType fios_type)
+{
+ return static_cast(fios_type >> FT_NUMBITS);
+}
+
/**
* The different kinds of subdirectories OpenTTD uses
*/
diff --git a/src/fios.cpp b/src/fios.cpp
index 00ed5a484c..8ed01152f0 100644
--- a/src/fios.cpp
+++ b/src/fios.cpp
@@ -29,17 +29,15 @@
#include "safeguards.h"
/* Variables to display file lists */
-SmallVector _fios_items;
static char *_fios_path;
static const char *_fios_path_last;
-SmallFiosItem _file_to_saveload;
SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING;
/* OS-specific functions are taken from their respective files (win32/unix/os2 .c) */
extern bool FiosIsRoot(const char *path);
extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
extern bool FiosIsHiddenFile(const struct dirent *ent);
-extern void FiosGetDrives();
+extern void FiosGetDrives(FileList &file_list);
extern bool FiosGetDiskFreeSpace(const char *path, uint64 *tot);
/* get the name of an oldstyle savegame */
@@ -65,11 +63,72 @@ int CDECL CompareFiosItems(const FiosItem *da, const FiosItem *db)
return r;
}
-/** Free the list of savegames. */
-void FiosFreeSavegameList()
+FileList::~FileList()
{
- _fios_items.Clear();
- _fios_items.Compact();
+ this->Clear();
+}
+
+/**
+ * Construct a file list with the given kind of files, for the stated purpose.
+ * @param abstract_filetype Kind of files to collect.
+ * @param fop Purpose of the collection, either #SLO_LOAD or #SLO_SAVE.
+ */
+void FileList::BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop)
+{
+ this->Clear();
+
+ assert(fop == SLO_LOAD || SLO_SAVE);
+ switch (abstract_filetype) {
+ case FT_NONE:
+ break;
+
+ case FT_SAVEGAME:
+ FiosGetSavegameList(fop, *this);
+ break;
+
+ case FT_SCENARIO:
+ FiosGetScenarioList(fop, *this);
+ break;
+
+ case FT_HEIGHTMAP:
+ FiosGetHeightmapList(fop, *this);
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+}
+
+/**
+ * Find file information of a file by its name from the file list.
+ * @param file The filename to return information about. Can be the actual name
+ * or a numbered entry into the filename list.
+ * @return The information on the file, or \c NULL if the file is not available.
+ */
+const FiosItem *FileList::FindItem(const char *file)
+{
+ for (const FiosItem *item = this->Begin(); item != this->End(); item++) {
+ if (strcmp(file, item->name) == 0) return item;
+ if (strcmp(file, item->title) == 0) return item;
+ }
+
+ /* If no name matches, try to parse it as number */
+ char *endptr;
+ int i = strtol(file, &endptr, 10);
+ if (file == endptr || *endptr != '\0') i = -1;
+
+ if (IsInsideMM(i, 0, this->Length())) return this->Get(i);
+
+ /* As a last effort assume it is an OpenTTD savegame and
+ * that the ".sav" part was not given. */
+ char long_file[MAX_PATH];
+ seprintf(long_file, lastof(long_file), "%s.sav", file);
+ for (const FiosItem *item = this->Begin(); item != this->End(); item++) {
+ if (strcmp(long_file, item->name) == 0) return item;
+ if (strcmp(long_file, item->title) == 0) return item;
+ }
+
+ return NULL;
}
/**
@@ -215,23 +274,24 @@ bool FiosDelete(const char *name)
return unlink(filename) == 0;
}
-typedef FiosType fios_getlist_callback_proc(SaveLoadDialogMode mode, const char *filename, const char *ext, char *title, const char *last);
+typedef FiosType fios_getlist_callback_proc(SaveLoadOperation fop, const char *filename, const char *ext, char *title, const char *last);
/**
* Scanner to scan for a particular type of FIOS file.
*/
class FiosFileScanner : public FileScanner {
- SaveLoadDialogMode mode; ///< The mode we want to search for
+ SaveLoadOperation fop; ///< The kind of file we are looking for.
fios_getlist_callback_proc *callback_proc; ///< Callback to check whether the file may be added
+ FileList &file_list; ///< Destination of the found files.
public:
/**
* Create the scanner
- * @param mode The mode we are in. Some modes don't allow 'parent'.
- * @param callback_proc The function that is called where you need to do the filtering.
+ * @param fop Purpose of collecting the list.
+ * @param callback_proc The function that is called where you need to do the filtering.
+ * @param file_list Destination of the found files.
*/
- FiosFileScanner(SaveLoadDialogMode mode, fios_getlist_callback_proc *callback_proc) :
- mode(mode),
- callback_proc(callback_proc)
+ FiosFileScanner(SaveLoadOperation fop, fios_getlist_callback_proc *callback_proc, FileList &file_list) :
+ fop(fop), callback_proc(callback_proc), file_list(file_list)
{}
/* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename);
@@ -251,14 +311,14 @@ bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, cons
char fios_title[64];
fios_title[0] = '\0'; // reset the title;
- FiosType type = this->callback_proc(this->mode, filename, ext, fios_title, lastof(fios_title));
+ FiosType type = this->callback_proc(this->fop, filename, ext, fios_title, lastof(fios_title));
if (type == FIOS_TYPE_INVALID) return false;
- for (const FiosItem *fios = _fios_items.Begin(); fios != _fios_items.End(); fios++) {
+ for (const FiosItem *fios = file_list.Begin(); fios != file_list.End(); fios++) {
if (strcmp(fios->name, filename) == 0) return false;
}
- FiosItem *fios = _fios_items.Append();
+ FiosItem *fios = file_list.Append();
#ifdef WIN32
struct _stat sb;
if (_tstat(OTTD2FS(filename), &sb) == 0) {
@@ -289,11 +349,12 @@ bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, cons
/**
* Fill the list of the files in a directory, according to some arbitrary rule.
- * @param mode The mode we are in. Some modes don't allow 'parent'.
- * @param callback_proc The function that is called where you need to do the filtering.
- * @param subdir The directory from where to start (global) searching.
+ * @param fop Purpose of collecting the list.
+ * @param callback_proc The function that is called where you need to do the filtering.
+ * @param subdir The directory from where to start (global) searching.
+ * @param file_list Destination of the found files.
*/
-static void FiosGetFileList(SaveLoadDialogMode mode, fios_getlist_callback_proc *callback_proc, Subdirectory subdir)
+static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *callback_proc, Subdirectory subdir, FileList &file_list)
{
struct stat sb;
struct dirent *dirent;
@@ -302,11 +363,11 @@ static void FiosGetFileList(SaveLoadDialogMode mode, fios_getlist_callback_proc
int sort_start;
char d_name[sizeof(fios->name)];
- _fios_items.Clear();
+ file_list.Clear();
/* A parent directory link exists if we are not in the root directory */
if (!FiosIsRoot(_fios_path)) {
- fios = _fios_items.Append();
+ fios = file_list.Append();
fios->type = FIOS_TYPE_PARENT;
fios->mtime = 0;
strecpy(fios->name, "..", lastof(fios->name));
@@ -322,7 +383,7 @@ static void FiosGetFileList(SaveLoadDialogMode mode, fios_getlist_callback_proc
if (FiosIsValidFile(_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) &&
(!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) {
- fios = _fios_items.Append();
+ fios = file_list.Append();
fios->type = FIOS_TYPE_DIR;
fios->mtime = 0;
strecpy(fios->name, d_name, lastof(fios->name));
@@ -337,27 +398,27 @@ static void FiosGetFileList(SaveLoadDialogMode mode, fios_getlist_callback_proc
{
SortingBits order = _savegame_sort_order;
_savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
- QSortT(_fios_items.Begin(), _fios_items.Length(), CompareFiosItems);
+ QSortT(file_list.files.Begin(), file_list.files.Length(), CompareFiosItems);
_savegame_sort_order = order;
}
/* This is where to start sorting for the filenames */
- sort_start = _fios_items.Length();
+ sort_start = file_list.Length();
/* Show files */
- FiosFileScanner scanner(mode, callback_proc);
+ FiosFileScanner scanner(fop, callback_proc, file_list);
if (subdir == NO_DIRECTORY) {
scanner.Scan(NULL, _fios_path, false);
} else {
scanner.Scan(NULL, subdir, true, true);
}
- QSortT(_fios_items.Get(sort_start), _fios_items.Length() - sort_start, CompareFiosItems);
+ QSortT(file_list.Get(sort_start), file_list.Length() - sort_start, CompareFiosItems);
/* Show drives */
- FiosGetDrives();
+ FiosGetDrives(file_list);
- _fios_items.Compact();
+ file_list.Compact();
}
/**
@@ -386,7 +447,7 @@ static void GetFileTitle(const char *file, char *title, const char *last, Subdir
/**
* Callback for FiosGetFileList. It tells if a file is a savegame or not.
- * @param mode Save/load mode.
+ * @param fop Purpose of collecting the list.
* @param file Name of the file to check.
* @param ext A pointer to the extension identifier inside file
* @param title Buffer if a callback wants to lookup the title of the file; NULL to skip the lookup
@@ -395,7 +456,7 @@ static void GetFileTitle(const char *file, char *title, const char *last, Subdir
* @see FiosGetFileList
* @see FiosGetSavegameList
*/
-FiosType FiosGetSavegameListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last)
+FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last)
{
/* Show savegame files
* .SAV OpenTTD saved game
@@ -411,7 +472,7 @@ FiosType FiosGetSavegameListCallback(SaveLoadDialogMode mode, const char *file,
return FIOS_TYPE_FILE;
}
- if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) {
+ if (fop == SLO_LOAD) {
if (strcasecmp(ext, ".ss1") == 0 || strcasecmp(ext, ".sv1") == 0 ||
strcasecmp(ext, ".sv2") == 0) {
if (title != NULL) GetOldSaveGameName(file, title, last);
@@ -424,10 +485,11 @@ FiosType FiosGetSavegameListCallback(SaveLoadDialogMode mode, const char *file,
/**
* Get a list of savegames.
- * @param mode Save/load mode.
+ * @param fop Purpose of collecting the list.
+ * @param file_list Destination of the found files.
* @see FiosGetFileList
*/
-void FiosGetSavegameList(SaveLoadDialogMode mode)
+void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list)
{
static char *fios_save_path = NULL;
static char *fios_save_path_last = NULL;
@@ -441,12 +503,12 @@ void FiosGetSavegameList(SaveLoadDialogMode mode)
_fios_path = fios_save_path;
_fios_path_last = fios_save_path_last;
- FiosGetFileList(mode, &FiosGetSavegameListCallback, NO_DIRECTORY);
+ FiosGetFileList(fop, &FiosGetSavegameListCallback, NO_DIRECTORY, file_list);
}
/**
* Callback for FiosGetFileList. It tells if a file is a scenario or not.
- * @param mode Save/load mode.
+ * @param fop Purpose of collecting the list.
* @param file Name of the file to check.
* @param ext A pointer to the extension identifier inside file
* @param title Buffer if a callback wants to lookup the title of the file
@@ -455,7 +517,7 @@ void FiosGetSavegameList(SaveLoadDialogMode mode)
* @see FiosGetFileList
* @see FiosGetScenarioList
*/
-static FiosType FiosGetScenarioListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last)
+static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last)
{
/* Show scenario files
* .SCN OpenTTD style scenario file
@@ -466,7 +528,7 @@ static FiosType FiosGetScenarioListCallback(SaveLoadDialogMode mode, const char
return FIOS_TYPE_SCENARIO;
}
- if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) {
+ if (fop == SLO_LOAD) {
if (strcasecmp(ext, ".sv0") == 0 || strcasecmp(ext, ".ss0") == 0 ) {
GetOldSaveGameName(file, title, last);
return FIOS_TYPE_OLD_SCENARIO;
@@ -478,10 +540,11 @@ static FiosType FiosGetScenarioListCallback(SaveLoadDialogMode mode, const char
/**
* Get a list of scenarios.
- * @param mode Save/load mode.
+ * @param fop Purpose of collecting the list.
+ * @param file_list Destination of the found files.
* @see FiosGetFileList
*/
-void FiosGetScenarioList(SaveLoadDialogMode mode)
+void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list)
{
static char *fios_scn_path = NULL;
static char *fios_scn_path_last = NULL;
@@ -499,10 +562,11 @@ void FiosGetScenarioList(SaveLoadDialogMode mode)
char base_path[MAX_PATH];
FioGetDirectory(base_path, lastof(base_path), SCENARIO_DIR);
- FiosGetFileList(mode, &FiosGetScenarioListCallback, (mode == SLD_LOAD_SCENARIO && strcmp(base_path, _fios_path) == 0) ? SCENARIO_DIR : NO_DIRECTORY);
+ Subdirectory subdir = (fop == SLO_LOAD && strcmp(base_path, _fios_path) == 0) ? SCENARIO_DIR : NO_DIRECTORY;
+ FiosGetFileList(fop, &FiosGetScenarioListCallback, subdir, file_list);
}
-static FiosType FiosGetHeightmapListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last)
+static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last)
{
/* Show heightmap files
* .PNG PNG Based heightmap files
@@ -548,9 +612,10 @@ static FiosType FiosGetHeightmapListCallback(SaveLoadDialogMode mode, const char
/**
* Get a list of heightmaps.
- * @param mode Save/load mode.
+ * @param fop Purpose of collecting the list.
+ * @param file_list Destination of the found files.
*/
-void FiosGetHeightmapList(SaveLoadDialogMode mode)
+void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list)
{
static char *fios_hmap_path = NULL;
static char *fios_hmap_path_last = NULL;
@@ -567,7 +632,8 @@ void FiosGetHeightmapList(SaveLoadDialogMode mode)
char base_path[MAX_PATH];
FioGetDirectory(base_path, lastof(base_path), HEIGHTMAP_DIR);
- FiosGetFileList(mode, &FiosGetHeightmapListCallback, strcmp(base_path, _fios_path) == 0 ? HEIGHTMAP_DIR : NO_DIRECTORY);
+ Subdirectory subdir = strcmp(base_path, _fios_path) == 0 ? HEIGHTMAP_DIR : NO_DIRECTORY;
+ FiosGetFileList(fop, &FiosGetHeightmapListCallback, subdir, file_list);
}
/**
diff --git a/src/fios.h b/src/fios.h
index b26fe00925..51e0c275a6 100644
--- a/src/fios.h
+++ b/src/fios.h
@@ -97,38 +97,6 @@ enum FileSlots {
MAX_FILE_SLOTS = 64
};
-/** Mode of the file dialogue window. */
-enum SaveLoadDialogMode {
- SLD_LOAD_GAME, ///< Load a game.
- SLD_LOAD_SCENARIO, ///< Load a scenario.
- SLD_SAVE_GAME, ///< Save a game.
- SLD_SAVE_SCENARIO, ///< Save a scenario.
- SLD_LOAD_HEIGHTMAP, ///< Load a heightmap.
- SLD_SAVE_HEIGHTMAP, ///< Save a heightmap.
-};
-
-/** The different types of files that the system knows about. */
-enum FileType {
- FT_NONE, ///< nothing to do
- FT_SAVEGAME, ///< old or new savegame
- FT_SCENARIO, ///< old or new scenario
- FT_HEIGHTMAP, ///< heightmap file
-};
-
-enum FiosType {
- FIOS_TYPE_DRIVE,
- FIOS_TYPE_PARENT,
- FIOS_TYPE_DIR,
- FIOS_TYPE_FILE,
- FIOS_TYPE_OLDFILE,
- FIOS_TYPE_SCENARIO,
- FIOS_TYPE_OLD_SCENARIO,
- FIOS_TYPE_DIRECT,
- FIOS_TYPE_PNG,
- FIOS_TYPE_BMP,
- FIOS_TYPE_INVALID = 255,
-};
-
/** Deals with finding savegames */
struct FiosItem {
FiosType type;
@@ -137,12 +105,95 @@ struct FiosItem {
char name[MAX_PATH];
};
-/** Deals with the type of the savegame, independent of extension */
-struct SmallFiosItem {
- int mode; ///< savegame/scenario type (old, new)
- FileType filetype; ///< what type of file are we dealing with
- char name[MAX_PATH]; ///< name
- char title[255]; ///< internal name of the game
+/** List of file information. */
+class FileList {
+public:
+ ~FileList();
+
+ /**
+ * Construct a new entry in the file list.
+ * @return Pointer to the new items to be initialized.
+ */
+ inline FiosItem *Append()
+ {
+ return this->files.Append();
+ }
+
+ /**
+ * Get the number of files in the list.
+ * @return The number of files stored in the list.
+ */
+ inline uint Length() const
+ {
+ return this->files.Length();
+ }
+
+ /**
+ * Get a pointer to the first file information.
+ * @return Address of the first file information.
+ */
+ inline const FiosItem *Begin() const
+ {
+ return this->files.Begin();
+ }
+
+ /**
+ * Get a pointer behind the last file information.
+ * @return Address behind the last file information.
+ */
+ inline const FiosItem *End() const
+ {
+ return this->files.End();
+ }
+
+ /**
+ * Get a pointer to the indicated file information. File information must exist.
+ * @return Address of the indicated existing file information.
+ */
+ inline const FiosItem *Get(uint index) const
+ {
+ return this->files.Get(index);
+ }
+
+ /**
+ * Get a pointer to the indicated file information. File information must exist.
+ * @return Address of the indicated existing file information.
+ */
+ inline FiosItem *Get(uint index)
+ {
+ return this->files.Get(index);
+ }
+
+ inline const FiosItem &operator[](uint index) const
+ {
+ return this->files[index];
+ }
+
+ /**
+ * Get a reference to the indicated file information. File information must exist.
+ * @return The requested file information.
+ */
+ inline FiosItem &operator[](uint index)
+ {
+ return this->files[index];
+ }
+
+ /** Remove all items from the list. */
+ inline void Clear()
+ {
+ this->files.Clear();
+ }
+
+ /** Compact the list down to the smallest block size boundary. */
+ inline void Compact()
+ {
+ this->files.Compact();
+ }
+
+ void BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop);
+ const FiosItem *FindItem(const char *file);
+
+ SmallVector files; ///< The list of files.
};
enum SortingBits {
@@ -154,18 +205,14 @@ enum SortingBits {
DECLARE_ENUM_AS_BIT_SET(SortingBits)
/* Variables to display file lists */
-extern SmallVector _fios_items;
-extern SmallFiosItem _file_to_saveload;
-extern SaveLoadDialogMode _saveload_mode;
extern SortingBits _savegame_sort_order;
-void ShowSaveLoadDialog(SaveLoadDialogMode mode);
+void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop);
-void FiosGetSavegameList(SaveLoadDialogMode mode);
-void FiosGetScenarioList(SaveLoadDialogMode mode);
-void FiosGetHeightmapList(SaveLoadDialogMode mode);
+void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list);
+void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list);
+void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list);
-void FiosFreeSavegameList();
const char *FiosBrowseTo(const FiosItem *item);
StringID FiosGetDescText(const char **path, uint64 *total_free);
@@ -173,13 +220,8 @@ bool FiosDelete(const char *name);
void FiosMakeHeightmapName(char *buf, const char *name, const char *last);
void FiosMakeSavegameName(char *buf, const char *name, const char *last);
-FiosType FiosGetSavegameListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last);
+FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last);
int CDECL CompareFiosItems(const FiosItem *a, const FiosItem *b);
-extern const TextColour _fios_colours[];
-
-void BuildFileList();
-void SetFiosType(const byte fiostype);
-
#endif /* FIOS_H */
diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp
index 9316deb658..e6cd9625cc 100644
--- a/src/fios_gui.cpp
+++ b/src/fios_gui.cpp
@@ -36,7 +36,6 @@
#include "safeguards.h"
-SaveLoadDialogMode _saveload_mode;
LoadCheckData _load_check_data; ///< Data loaded from save during SL_LOAD_CHECK.
static bool _fios_path_changed;
@@ -187,33 +186,24 @@ static const NWidgetPart _nested_save_dialog_widgets[] = {
EndContainer(),
};
-/** Colours for fios types, indexed by #FiosType. */
-const TextColour _fios_colours[] = {
- TC_LIGHT_BLUE, TC_DARK_GREEN, TC_DARK_GREEN, TC_ORANGE, TC_LIGHT_BROWN,
- TC_ORANGE, TC_LIGHT_BROWN, TC_ORANGE, TC_ORANGE, TC_YELLOW
+/** Text colours of #DetailedFileType fios entries in the window. */
+static const TextColour _fios_colours[] = {
+ TC_LIGHT_BROWN, // DFT_OLD_GAME_FILE
+ TC_ORANGE, // DFT_GAME_FILE
+ TC_YELLOW, // DFT_HEIGHTMAP_BMP
+ TC_ORANGE, // DFT_HEIGHTMAP_PNG
+ TC_LIGHT_BLUE, // DFT_FIOS_DRIVE
+ TC_DARK_GREEN, // DFT_FIOS_PARENT
+ TC_DARK_GREEN, // DFT_FIOS_DIR
+ TC_ORANGE, // DFT_FIOS_DIRECT
};
-void BuildFileList()
-{
- _fios_path_changed = true;
- FiosFreeSavegameList();
- switch (_saveload_mode) {
- case SLD_LOAD_SCENARIO:
- case SLD_SAVE_SCENARIO:
- FiosGetScenarioList(_saveload_mode); break;
- case SLD_SAVE_HEIGHTMAP:
- case SLD_LOAD_HEIGHTMAP:
- FiosGetHeightmapList(_saveload_mode); break;
-
- default: FiosGetSavegameList(_saveload_mode); break;
- }
-
- /* Invalidate saveload window */
- InvalidateWindowData(WC_SAVELOAD, 0, 2, true);
-}
-
-static void MakeSortedSaveGameList()
+/**
+ * Sort the collected list save games prior to displaying it in the save/load gui.
+ * @param [inout] file_list List of save game files found in the directory.
+ */
+static void SortSaveGameList(FileList &file_list)
{
uint sort_start = 0;
uint sort_end = 0;
@@ -222,7 +212,7 @@ static void MakeSortedSaveGameList()
* Drives (A:\ (windows only) are always under the files (FIOS_TYPE_DRIVE)
* Only sort savegames/scenarios, not directories
*/
- for (const FiosItem *item = _fios_items.Begin(); item != _fios_items.End(); item++) {
+ for (const FiosItem *item = file_list.Begin(); item != file_list.End(); item++) {
switch (item->type) {
case FIOS_TYPE_DIR: sort_start++; break;
case FIOS_TYPE_PARENT: sort_start++; break;
@@ -231,15 +221,18 @@ static void MakeSortedSaveGameList()
}
}
- uint s_amount = _fios_items.Length() - sort_start - sort_end;
- QSortT(_fios_items.Get(sort_start), s_amount, CompareFiosItems);
+ uint s_amount = file_list.Length() - sort_start - sort_end;
+ QSortT(file_list.Get(sort_start), s_amount, CompareFiosItems);
}
struct SaveLoadWindow : public Window {
private:
QueryString filename_editbox; ///< Filename editbox.
+ AbstractFileType abstract_filetype; /// Type of file to select.
+ SaveLoadOperation fop; ///< File operation to perform.
+ FileList fios_items; ///< Save game list.
FiosItem o_dir;
- const FiosItem *selected;
+ const FiosItem *selected; ///< Selected game in #fios_items, or \c NULL.
Scrollbar *vscroll;
public:
@@ -250,35 +243,56 @@ public:
this->filename_editbox.text.UpdateSize();
}
- SaveLoadWindow(WindowDesc *desc, SaveLoadDialogMode mode) : Window(desc), filename_editbox(64)
+ SaveLoadWindow(WindowDesc *desc, AbstractFileType abstract_filetype, SaveLoadOperation fop)
+ : Window(desc), filename_editbox(64), abstract_filetype(abstract_filetype), fop(fop)
{
- static const StringID saveload_captions[] = {
- STR_SAVELOAD_LOAD_CAPTION,
- STR_SAVELOAD_LOAD_SCENARIO,
- STR_SAVELOAD_SAVE_CAPTION,
- STR_SAVELOAD_SAVE_SCENARIO,
- STR_SAVELOAD_LOAD_HEIGHTMAP,
- STR_SAVELOAD_SAVE_HEIGHTMAP,
- };
- assert((uint)mode < lengthof(saveload_captions));
+ assert(this->fop == SLO_SAVE || this->fop == SLO_LOAD);
- /* Use an array to define what will be the current file type being handled
- * by current file mode */
- switch (mode) {
- case SLD_SAVE_GAME: this->GenerateFileName(); break;
- case SLD_SAVE_HEIGHTMAP:
- case SLD_SAVE_SCENARIO: this->filename_editbox.text.Assign("UNNAMED"); break;
- default: break;
+ /* For saving, construct an initial file name. */
+ if (this->fop == SLO_SAVE) {
+ switch (this->abstract_filetype) {
+ case FT_SAVEGAME:
+ this->GenerateFileName();
+ break;
+
+ case FT_SCENARIO:
+ case FT_HEIGHTMAP:
+ this->filename_editbox.text.Assign("UNNAMED");
+ break;
+
+ default:
+ NOT_REACHED();
+ }
}
-
this->querystrings[WID_SL_SAVE_OSK_TITLE] = &this->filename_editbox;
this->filename_editbox.ok_button = WID_SL_SAVE_GAME;
this->CreateNestedTree(true);
- if (mode == SLD_LOAD_GAME) this->GetWidget(WID_SL_CONTENT_DOWNLOAD_SEL)->SetDisplayedPlane(SZSP_HORIZONTAL);
- this->GetWidget(WID_SL_CAPTION)->widget_data = saveload_captions[mode];
- this->vscroll = this->GetScrollbar(WID_SL_SCROLLBAR);
+ if (this->fop == SLO_LOAD && this->abstract_filetype == FT_SAVEGAME) {
+ this->GetWidget(WID_SL_CONTENT_DOWNLOAD_SEL)->SetDisplayedPlane(SZSP_HORIZONTAL);
+ }
+ /* Select caption string of the window. */
+ StringID caption_string;
+ switch (this->abstract_filetype) {
+ case FT_SAVEGAME:
+ caption_string = (this->fop == SLO_SAVE) ? STR_SAVELOAD_SAVE_CAPTION : STR_SAVELOAD_LOAD_CAPTION;
+ break;
+
+ case FT_SCENARIO:
+ caption_string = (this->fop == SLO_SAVE) ? STR_SAVELOAD_SAVE_SCENARIO : STR_SAVELOAD_LOAD_SCENARIO;
+ break;
+
+ case FT_HEIGHTMAP:
+ caption_string = (this->fop == SLO_SAVE) ? STR_SAVELOAD_SAVE_HEIGHTMAP : STR_SAVELOAD_LOAD_HEIGHTMAP;
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+ this->GetWidget(WID_SL_CAPTION)->widget_data = caption_string;
+
+ this->vscroll = this->GetScrollbar(WID_SL_SCROLLBAR);
this->FinishInitNested(0);
this->LowerWidget(WID_SL_DRIVES_DIRECTORIES_LIST);
@@ -294,20 +308,18 @@ public:
ResetObjectToPlace();
+ /* Select the initial directory. */
o_dir.type = FIOS_TYPE_DIRECT;
- switch (_saveload_mode) {
- case SLD_SAVE_GAME:
- case SLD_LOAD_GAME:
+ switch (this->abstract_filetype) {
+ case FT_SAVEGAME:
FioGetDirectory(o_dir.name, lastof(o_dir.name), SAVE_DIR);
break;
- case SLD_SAVE_SCENARIO:
- case SLD_LOAD_SCENARIO:
+ case FT_SCENARIO:
FioGetDirectory(o_dir.name, lastof(o_dir.name), SCENARIO_DIR);
break;
- case SLD_SAVE_HEIGHTMAP:
- case SLD_LOAD_HEIGHTMAP:
+ case FT_HEIGHTMAP:
FioGetDirectory(o_dir.name, lastof(o_dir.name), HEIGHTMAP_DIR);
break;
@@ -316,9 +328,7 @@ public:
}
/* Focus the edit box by default in the save windows */
- if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO || _saveload_mode == SLD_SAVE_HEIGHTMAP) {
- this->SetFocusedWidget(WID_SL_SAVE_OSK_TITLE);
- }
+ if (this->fop == SLO_SAVE) this->SetFocusedWidget(WID_SL_SAVE_OSK_TITLE);
}
virtual ~SaveLoadWindow()
@@ -327,7 +337,6 @@ public:
if (!_networking && _game_mode != GM_EDITOR && _game_mode != GM_MENU) {
DoCommandP(0, PM_PAUSED_SAVELOAD, 0, CMD_PAUSE);
}
- FiosFreeSavegameList();
}
virtual void DrawWidget(const Rect &r, int widget) const
@@ -360,13 +369,13 @@ public:
GfxFillRect(r.left + 1, r.top + 1, r.right, r.bottom, PC_BLACK);
uint y = r.top + WD_FRAMERECT_TOP;
- for (uint pos = this->vscroll->GetPosition(); pos < _fios_items.Length(); pos++) {
- const FiosItem *item = _fios_items.Get(pos);
+ for (uint pos = this->vscroll->GetPosition(); pos < this->fios_items.Length(); pos++) {
+ const FiosItem *item = this->fios_items.Get(pos);
if (item == this->selected) {
GfxFillRect(r.left + 1, y, r.right, y + this->resize.step_height, PC_DARK_BLUE);
}
- DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, item->title, _fios_colours[item->type]);
+ DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, item->title, _fios_colours[GetDetailedFileType(item->type)]);
y += this->resize.step_height;
if (y >= this->vscroll->GetCapacity() * this->resize.step_height + r.top + WD_FRAMERECT_TOP) break;
}
@@ -421,7 +430,7 @@ public:
if (y > y_max) break;
/* Hide current date for scenarios */
- if (_saveload_mode != SLD_LOAD_SCENARIO && _saveload_mode != SLD_SAVE_SCENARIO) {
+ if (this->abstract_filetype != FT_SCENARIO) {
/* Current date */
SetDParam(0, _load_check_data.current_date);
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CURRENT_DATE);
@@ -429,7 +438,7 @@ public:
}
/* Hide the NewGRF stuff when saving. We also hide the button. */
- if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) {
+ if (this->fop == SLO_LOAD && (this->abstract_filetype == FT_SAVEGAME || this->abstract_filetype == FT_SCENARIO)) {
y += WD_PAR_VSEP_NORMAL;
if (y > y_max) break;
@@ -442,7 +451,7 @@ public:
if (y > y_max) break;
/* Hide the company stuff for scenarios */
- if (_saveload_mode != SLD_LOAD_SCENARIO && _saveload_mode != SLD_SAVE_SCENARIO) {
+ if (this->abstract_filetype != FT_SCENARIO) {
y += FONT_HEIGHT_NORMAL;
if (y > y_max) break;
@@ -495,10 +504,10 @@ public:
{
if (_savegame_sort_dirty) {
_savegame_sort_dirty = false;
- MakeSortedSaveGameList();
+ SortSaveGameList(this->fios_items);
}
- this->vscroll->SetCount(_fios_items.Length());
+ this->vscroll->SetCount(this->fios_items.Length());
this->DrawWidgets();
}
@@ -527,14 +536,14 @@ public:
case WID_SL_LOAD_BUTTON:
if (this->selected != NULL && !_load_check_data.HasErrors()) {
const char *name = FiosBrowseTo(this->selected);
- SetFiosType(this->selected->type);
+ _file_to_saveload.SetMode(this->selected->type);
+ _file_to_saveload.SetName(name);
+ _file_to_saveload.SetTitle(this->selected->title);
- strecpy(_file_to_saveload.name, name, lastof(_file_to_saveload.name));
- strecpy(_file_to_saveload.title, this->selected->title, lastof(_file_to_saveload.title));
-
- if (_saveload_mode == SLD_LOAD_HEIGHTMAP) {
+ if (this->abstract_filetype == FT_HEIGHTMAP) {
delete this;
ShowHeightmapLoad();
+
} else if (!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()) {
_switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_SCENARIO : SM_LOAD_GAME;
ClearErrorMessages();
@@ -563,7 +572,7 @@ public:
int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WD_FRAMERECT_TOP);
if (y == INT_MAX) return;
- const FiosItem *file = _fios_items.Get(y);
+ const FiosItem *file = this->fios_items.Get(y);
const char *name = FiosBrowseTo(file);
if (name != NULL) {
@@ -572,28 +581,32 @@ public:
this->selected = file;
_load_check_data.Clear();
- if (file->type == FIOS_TYPE_FILE || file->type == FIOS_TYPE_SCENARIO) {
- SaveOrLoad(name, SL_LOAD_CHECK, NO_DIRECTORY, false);
+ if (GetDetailedFileType(file->type) == DFT_GAME_FILE) {
+ /* Other detailed file types cannot be checked before. */
+ SaveOrLoad(name, SLO_CHECK, DFT_GAME_FILE, NO_DIRECTORY, false);
}
this->InvalidateData(1);
}
- if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO || _saveload_mode == SLD_SAVE_HEIGHTMAP) {
+ if (this->fop == SLO_SAVE) {
/* Copy clicked name to editbox */
this->filename_editbox.text.Assign(file->title);
this->SetWidgetDirty(WID_SL_SAVE_OSK_TITLE);
}
} else if (!_load_check_data.HasErrors()) {
this->selected = file;
- if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) {
- this->OnClick(pt, WID_SL_LOAD_BUTTON, 1);
- } else if (_saveload_mode == SLD_LOAD_HEIGHTMAP) {
- SetFiosType(file->type);
- strecpy(_file_to_saveload.name, name, lastof(_file_to_saveload.name));
- strecpy(_file_to_saveload.title, file->title, lastof(_file_to_saveload.title));
+ if (this->fop == SLO_LOAD) {
+ if (this->abstract_filetype == FT_SAVEGAME || this->abstract_filetype == FT_SCENARIO) {
+ this->OnClick(pt, WID_SL_LOAD_BUTTON, 1);
+ } else {
+ assert(this->abstract_filetype == FT_HEIGHTMAP);
+ _file_to_saveload.SetMode(file->type);
+ _file_to_saveload.SetName(name);
+ _file_to_saveload.SetTitle(file->title);
- delete this;
- ShowHeightmapLoad();
+ delete this;
+ ShowHeightmapLoad();
+ }
}
}
} else {
@@ -608,10 +621,11 @@ public:
ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
} else {
#if defined(ENABLE_NETWORK)
- switch (_saveload_mode) {
+ assert(this->fop == SLO_LOAD);
+ switch (this->abstract_filetype) {
default: NOT_REACHED();
- case SLD_LOAD_SCENARIO: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_SCENARIO); break;
- case SLD_LOAD_HEIGHTMAP: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_HEIGHTMAP); break;
+ case FT_SCENARIO: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_SCENARIO); break;
+ case FT_HEIGHTMAP: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_HEIGHTMAP); break;
}
#endif
}
@@ -639,9 +653,8 @@ public:
virtual void OnTimeout()
{
- /* This test protects against using widgets 11 and 12 which are only available
- * in those saveload modes. */
- if (!(_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO || _saveload_mode == SLD_SAVE_HEIGHTMAP)) return;
+ /* Widgets WID_SL_DELETE_SELECTION and WID_SL_SAVE_GAME only exist when saving to a file. */
+ if (this->fop != SLO_SAVE) return;
if (this->IsWidgetLowered(WID_SL_DELETE_SELECTION)) { // Delete button clicked
if (!FiosDelete(this->filename_editbox.text.buf)) {
@@ -649,10 +662,10 @@ public:
} else {
this->InvalidateData();
/* Reset file name to current date on successful delete */
- if (_saveload_mode == SLD_SAVE_GAME) GenerateFileName();
+ if (this->abstract_filetype == FT_SAVEGAME) GenerateFileName();
}
} else if (this->IsWidgetLowered(WID_SL_SAVE_GAME)) { // Save button clicked
- if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
+ if (this->abstract_filetype == FT_SAVEGAME || this->abstract_filetype == FT_SCENARIO) {
_switch_mode = SM_SAVE_GAME;
FiosMakeSavegameName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name));
} else {
@@ -683,28 +696,40 @@ public:
this->selected = NULL;
_load_check_data.Clear();
if (!gui_scope) break;
- BuildFileList();
+
+ _fios_path_changed = true;
+ this->fios_items.BuildFileList(this->abstract_filetype, this->fop);
+ this->vscroll->SetCount(this->fios_items.Length());
+ this->selected = NULL;
+ _load_check_data.Clear();
/* FALL THROUGH */
case 1:
/* Selection changes */
if (!gui_scope) break;
- if (_saveload_mode == SLD_LOAD_HEIGHTMAP) {
- this->SetWidgetDisabledState(WID_SL_LOAD_BUTTON, this->selected == NULL || _load_check_data.HasErrors());
+
+ if (this->fop != SLO_LOAD) break;
+
+ switch (this->abstract_filetype) {
+ case FT_HEIGHTMAP:
+ this->SetWidgetDisabledState(WID_SL_LOAD_BUTTON, this->selected == NULL || _load_check_data.HasErrors());
+ break;
+
+ case FT_SAVEGAME:
+ case FT_SCENARIO: {
+ bool disabled = this->selected == NULL || _load_check_data.HasErrors();
+ if (!_settings_client.gui.UserIsAllowedToChangeNewGRFs()) {
+ disabled |= _load_check_data.HasNewGrfs() && _load_check_data.grf_compatibility == GLC_NOT_FOUND;
+ }
+ this->SetWidgetDisabledState(WID_SL_LOAD_BUTTON, disabled);
+ this->SetWidgetDisabledState(WID_SL_NEWGRF_INFO, !_load_check_data.HasNewGrfs());
+ this->SetWidgetDisabledState(WID_SL_MISSING_NEWGRFS,
+ !_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility == GLC_ALL_GOOD);
+ break;
+ }
+
+ default:
+ NOT_REACHED();
}
- if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) {
- this->SetWidgetDisabledState(WID_SL_LOAD_BUTTON,
- this->selected == NULL || _load_check_data.HasErrors() || !(!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()));
- this->SetWidgetDisabledState(WID_SL_NEWGRF_INFO,
- !_load_check_data.HasNewGrfs());
- this->SetWidgetDisabledState(WID_SL_MISSING_NEWGRFS,
- !_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility == GLC_ALL_GOOD);
- }
- break;
- case 2:
- /* _fios_items changed */
- this->vscroll->SetCount(_fios_items.Length());
- this->selected = NULL;
- _load_check_data.Clear();
break;
}
}
@@ -734,70 +759,24 @@ static WindowDesc _save_dialog_desc(
_nested_save_dialog_widgets, lengthof(_nested_save_dialog_widgets)
);
-/**
- * These values are used to convert the file/operations mode into a corresponding file type.
- * So each entry, as expressed by the related comment, is based on the enum
- */
-static const FileType _file_modetotype[] = {
- FT_SAVEGAME, // used for SLD_LOAD_GAME
- FT_SCENARIO, // used for SLD_LOAD_SCENARIO
- FT_SAVEGAME, // used for SLD_SAVE_GAME
- FT_SCENARIO, // used for SLD_SAVE_SCENARIO
- FT_HEIGHTMAP, // used for SLD_LOAD_HEIGHTMAP
- FT_HEIGHTMAP, // used for SLD_SAVE_HEIGHTMAP
-};
-
/**
* Launch save/load dialog in the given mode.
- * @param mode Save/load mode.
+ * @param abstract_filetype Kind of file to handle.
+ * @param fop File operation to perform (load or save).
*/
-void ShowSaveLoadDialog(SaveLoadDialogMode mode)
+void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop)
{
DeleteWindowById(WC_SAVELOAD, 0);
WindowDesc *sld;
- switch (mode) {
- case SLD_SAVE_GAME:
- case SLD_SAVE_SCENARIO:
- case SLD_SAVE_HEIGHTMAP:
- sld = &_save_dialog_desc; break;
- case SLD_LOAD_HEIGHTMAP:
- sld = &_load_heightmap_dialog_desc; break;
- default:
- sld = &_load_dialog_desc; break;
+ if (fop == SLO_SAVE) {
+ sld = &_save_dialog_desc;
+ } else {
+ /* Dialogue for loading a file. */
+ sld = (abstract_filetype == FT_HEIGHTMAP) ? &_load_heightmap_dialog_desc : &_load_dialog_desc;
}
- _saveload_mode = mode;
- _file_to_saveload.filetype = _file_modetotype[mode];
+ _file_to_saveload.abstract_ftype = abstract_filetype;
- new SaveLoadWindow(sld, mode);
-}
-
-void SetFiosType(const byte fiostype)
-{
- switch (fiostype) {
- case FIOS_TYPE_FILE:
- case FIOS_TYPE_SCENARIO:
- _file_to_saveload.mode = SL_LOAD;
- break;
-
- case FIOS_TYPE_OLDFILE:
- case FIOS_TYPE_OLD_SCENARIO:
- _file_to_saveload.mode = SL_OLD_LOAD;
- break;
-
-#ifdef WITH_PNG
- case FIOS_TYPE_PNG:
- _file_to_saveload.mode = SL_PNG;
- break;
-#endif /* WITH_PNG */
-
- case FIOS_TYPE_BMP:
- _file_to_saveload.mode = SL_BMP;
- break;
-
- default:
- _file_to_saveload.mode = SL_INVALID;
- break;
- }
+ new SaveLoadWindow(sld, abstract_filetype, fop);
}
diff --git a/src/genworld.cpp b/src/genworld.cpp
index 2b2dfb5fd7..a08b323116 100644
--- a/src/genworld.cpp
+++ b/src/genworld.cpp
@@ -204,7 +204,7 @@ static void _GenerateWorld(void *)
if (_debug_desync_level > 0) {
char name[MAX_PATH];
seprintf(name, lastof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
- SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR, false);
+ SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false);
}
} catch (...) {
BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP, true);
diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp
index 741fd75d1c..359709e361 100644
--- a/src/genworld_gui.cpp
+++ b/src/genworld_gui.cpp
@@ -26,6 +26,7 @@
#include "town.h"
#include "core/geometry_func.hpp"
#include "core/random_func.hpp"
+#include "saveload/saveload.h"
#include "progress.h"
#include "error.h"
@@ -832,7 +833,7 @@ static void _ShowGenerateLandscape(GenerateLandscapeWindowMode mode)
if (mode == GLWM_HEIGHTMAP) {
/* If the function returns negative, it means there was a problem loading the heightmap */
- if (!GetHeightmapDimensions(_file_to_saveload.name, &x, &y)) return;
+ if (!GetHeightmapDimensions(_file_to_saveload.detail_ftype, _file_to_saveload.name, &x, &y)) return;
}
WindowDesc *desc = (mode == GLWM_HEIGHTMAP) ? &_heightmap_load_desc : &_generate_landscape_desc;
diff --git a/src/heightmap.cpp b/src/heightmap.cpp
index ec31257287..630dc69d7e 100644
--- a/src/heightmap.cpp
+++ b/src/heightmap.cpp
@@ -102,7 +102,7 @@ static void ReadHeightmapPNGImageData(byte *map, png_structp png_ptr, png_infop
* If map == NULL only the size of the PNG is read, otherwise a map
* with grayscale pixels is allocated and assigned to *map.
*/
-static bool ReadHeightmapPNG(char *filename, uint *x, uint *y, byte **map)
+static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, byte **map)
{
FILE *fp;
png_structp png_ptr = NULL;
@@ -232,7 +232,7 @@ static void ReadHeightmapBMPImageData(byte *map, BmpInfo *info, BmpData *data)
* If map == NULL only the size of the BMP is read, otherwise a map
* with grayscale pixels is allocated and assigned to *map.
*/
-static bool ReadHeightmapBMP(char *filename, uint *x, uint *y, byte **map)
+static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, byte **map)
{
FILE *f;
BmpInfo info;
@@ -444,45 +444,56 @@ void FixSlopes()
}
/**
- * Reads the heightmap with the correct file reader
+ * Reads the heightmap with the correct file reader.
+ * @param dft Type of image file.
+ * @param filename Name of the file to load.
+ * @param [out] x Length of the image.
+ * @param [out] y Height of the image.
+ * @param [inout] map If not \c NULL, destination to store the loaded block of image data.
+ * @return Whether loading was successful.
*/
-static bool ReadHeightMap(char *filename, uint *x, uint *y, byte **map)
+static bool ReadHeightMap(DetailedFileType dft, const char *filename, uint *x, uint *y, byte **map)
{
- switch (_file_to_saveload.mode) {
- default: NOT_REACHED();
+ switch (dft) {
+ default:
+ NOT_REACHED();
+
#ifdef WITH_PNG
- case SL_PNG:
+ case DFT_HEIGHTMAP_PNG:
return ReadHeightmapPNG(filename, x, y, map);
#endif /* WITH_PNG */
- case SL_BMP:
+
+ case DFT_HEIGHTMAP_BMP:
return ReadHeightmapBMP(filename, x, y, map);
}
}
/**
* Get the dimensions of a heightmap.
+ * @param dft Type of image file.
* @param filename to query
* @param x dimension x
* @param y dimension y
* @return Returns false if loading of the image failed.
*/
-bool GetHeightmapDimensions(char *filename, uint *x, uint *y)
+bool GetHeightmapDimensions(DetailedFileType dft, const char *filename, uint *x, uint *y)
{
- return ReadHeightMap(filename, x, y, NULL);
+ return ReadHeightMap(dft, filename, x, y, NULL);
}
/**
* Load a heightmap from file and change the map in his current dimensions
* to a landscape representing the heightmap.
* It converts pixels to height. The brighter, the higher.
+ * @param dft Type of image file.
* @param filename of the heightmap file to be imported
*/
-void LoadHeightmap(char *filename)
+void LoadHeightmap(DetailedFileType dft, const char *filename)
{
uint x, y;
byte *map = NULL;
- if (!ReadHeightMap(filename, &x, &y, &map)) {
+ if (!ReadHeightMap(dft, filename, &x, &y, &map)) {
free(map);
return;
}
diff --git a/src/heightmap.h b/src/heightmap.h
index 08ae200ece..67349df483 100644
--- a/src/heightmap.h
+++ b/src/heightmap.h
@@ -12,6 +12,8 @@
#ifndef HEIGHTMAP_H
#define HEIGHTMAP_H
+#include "fileio_type.h"
+
/**
* Order of these enums has to be the same as in lang/english.txt
* Otherwise you will get inconsistent behaviour.
@@ -21,8 +23,8 @@ enum HeightmapRotation {
HM_CLOCKWISE, ///< Rotate the map clockwise 45 degrees
};
-bool GetHeightmapDimensions(char *filename, uint *x, uint *y);
-void LoadHeightmap(char *filename);
+bool GetHeightmapDimensions(DetailedFileType dft, const char *filename, uint *x, uint *y);
+void LoadHeightmap(DetailedFileType dft, const char *filename);
void FlatEmptyWorld(byte tile_height);
void FixSlopes();
diff --git a/src/intro_gui.cpp b/src/intro_gui.cpp
index de8b379392..a09a59a10d 100644
--- a/src/intro_gui.cpp
+++ b/src/intro_gui.cpp
@@ -111,9 +111,9 @@ struct SelectGameWindow : public Window {
}
break;
- case WID_SGI_LOAD_GAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
- case WID_SGI_PLAY_SCENARIO: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
- case WID_SGI_PLAY_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
+ case WID_SGI_LOAD_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
+ case WID_SGI_PLAY_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_LOAD); break;
+ case WID_SGI_PLAY_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_LOAD); break;
case WID_SGI_EDIT_SCENARIO: StartScenarioEditor(); break;
case WID_SGI_PLAY_NETWORK:
diff --git a/src/landscape.cpp b/src/landscape.cpp
index d1c73fd42b..185e84a80b 100644
--- a/src/landscape.cpp
+++ b/src/landscape.cpp
@@ -31,6 +31,7 @@
#include "object_base.h"
#include "company_func.h"
#include "pathfinder/npf/aystar.h"
+#include "saveload/saveload.h"
#include
#include
@@ -1221,7 +1222,7 @@ void GenerateLandscape(byte mode)
if (mode == GWM_HEIGHTMAP) {
SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
- LoadHeightmap(_file_to_saveload.name);
+ LoadHeightmap(_file_to_saveload.detail_ftype, _file_to_saveload.name);
IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
} else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp
index d4d294146e..edfe4587f3 100644
--- a/src/network/network_client.cpp
+++ b/src/network/network_client.cpp
@@ -520,7 +520,7 @@ bool ClientNetworkGameSocketHandler::IsConnected()
* DEF_CLIENT_RECEIVE_COMMAND has parameter: Packet *p
************/
-extern bool SafeLoad(const char *filename, int mode, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL);
+extern bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL);
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FULL(Packet *p)
{
@@ -836,7 +836,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
/* The map is done downloading, load it */
ClearErrorMessages();
- bool load_success = SafeLoad(NULL, SL_LOAD, GM_NORMAL, NO_DIRECTORY, lf);
+ bool load_success = SafeLoad(NULL, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, lf);
/* Long savegame loads shouldn't affect the lag calculation! */
this->last_packet = _realtime_tick;
diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp
index 7c04ad4e02..520c4f60a8 100644
--- a/src/network/network_gui.cpp
+++ b/src/network/network_gui.cpp
@@ -1187,17 +1187,17 @@ struct NetworkStartServerWindow : public Window {
case WID_NSS_LOAD_GAME:
_is_network_server = true;
- ShowSaveLoadDialog(SLD_LOAD_GAME);
+ ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD);
break;
case WID_NSS_PLAY_SCENARIO:
_is_network_server = true;
- ShowSaveLoadDialog(SLD_LOAD_SCENARIO);
+ ShowSaveLoadDialog(FT_SCENARIO, SLO_LOAD);
break;
case WID_NSS_PLAY_HEIGHTMAP:
_is_network_server = true;
- ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP);
+ ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_LOAD);
break;
}
}
diff --git a/src/openttd.cpp b/src/openttd.cpp
index c149ebbd4d..cc382bdbf0 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -123,6 +123,25 @@ void CDECL error(const char *s, ...)
abort();
}
+void CDECL assert_msg_error(int line, const char *file, const char *expr, const char *str, ...)
+{
+ va_list va;
+ char buf[2048];
+
+ char *b = buf;
+ b += seprintf(b, lastof(buf), "Assertion failed at line %i of %s: %s\n\t", line, file, expr);
+
+ va_start(va, str);
+ vseprintf(b, lastof(buf), str, va);
+ va_end(va);
+
+ ShowOSErrorBox(buf, true);
+
+ /* Set the error message for the crash log and then invoke it. */
+ CrashLog::SetErrorMessage(buf);
+ abort();
+}
+
/**
* Shows some information on the console/a popup box depending on the OS.
* @param str the text to show.
@@ -328,7 +347,7 @@ static void LoadIntroGame(bool load_newgrfs = true)
SetupColoursAndInitialWindow();
/* Load the default opening screen savegame */
- if (SaveOrLoad("opntitle.dat", SL_LOAD, BASESET_DIR) != SL_OK) {
+ if (SaveOrLoad("opntitle.dat", SLO_LOAD, DFT_GAME_FILE, BASESET_DIR) != SL_OK) {
GenerateWorld(GWM_EMPTY, 64, 64); // if failed loading, make empty world.
WaitTillGeneratedWorld();
SetLocalCompany(COMPANY_SPECTATOR);
@@ -618,15 +637,16 @@ int openttd_main(int argc, char *argv[])
case 'e': _switch_mode = (_switch_mode == SM_LOAD_GAME || _switch_mode == SM_LOAD_SCENARIO ? SM_LOAD_SCENARIO : SM_EDITOR); break;
case 'g':
if (mgo.opt != NULL) {
- strecpy(_file_to_saveload.name, mgo.opt, lastof(_file_to_saveload.name));
- _switch_mode = (_switch_mode == SM_EDITOR || _switch_mode == SM_LOAD_SCENARIO ? SM_LOAD_SCENARIO : SM_LOAD_GAME);
- _file_to_saveload.mode = SL_LOAD;
+ _file_to_saveload.SetName(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 */
const char *t = strrchr(_file_to_saveload.name, '.');
if (t != NULL) {
- FiosType ft = FiosGetSavegameListCallback(SLD_LOAD_GAME, _file_to_saveload.name, t, NULL, NULL);
- if (ft != FIOS_TYPE_INVALID) SetFiosType(ft);
+ FiosType ft = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name, t, NULL, NULL);
+ if (ft != FIOS_TYPE_INVALID) _file_to_saveload.SetMode(ft);
}
break;
@@ -647,10 +667,10 @@ int openttd_main(int argc, char *argv[])
char title[80];
title[0] = '\0';
- FiosGetSavegameListCallback(SLD_LOAD_GAME, mgo.opt, strrchr(mgo.opt, '.'), title, lastof(title));
+ FiosGetSavegameListCallback(SLO_LOAD, mgo.opt, strrchr(mgo.opt, '.'), title, lastof(title));
_load_check_data.Clear();
- SaveOrLoadResult res = SaveOrLoad(mgo.opt, SL_LOAD_CHECK, SAVE_DIR, false);
+ SaveOrLoadResult res = SaveOrLoad(mgo.opt, SLO_CHECK, DFT_GAME_FILE, SAVE_DIR, false);
if (res != SL_OK || _load_check_data.HasErrors()) {
fprintf(stderr, "Failed to open savegame\n");
if (_load_check_data.HasErrors()) {
@@ -997,14 +1017,15 @@ static void MakeNewEditorWorld()
* @param subdir default directory to look for filename, set to 0 if not needed
* @param lf Load filter to use, if NULL: use filename + subdir.
*/
-bool SafeLoad(const char *filename, int mode, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL)
+bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL)
{
- assert(mode == SL_LOAD || (lf == NULL && mode == SL_OLD_LOAD));
+ assert(fop == SLO_LOAD);
+ assert(dft == DFT_GAME_FILE || (lf == NULL && dft == DFT_OLD_GAME_FILE));
GameMode ogm = _game_mode;
_game_mode = newgm;
- switch (lf == NULL ? SaveOrLoad(filename, mode, subdir) : LoadWithFilter(lf)) {
+ switch (lf == NULL ? SaveOrLoad(filename, fop, dft, subdir) : LoadWithFilter(lf)) {
case SL_OK: return true;
case SL_REINIT:
@@ -1093,11 +1114,11 @@ void SwitchToMode(SwitchMode new_mode)
ResetGRFConfig(true);
ResetWindowSystem();
- if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL, NO_DIRECTORY)) {
+ if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_NORMAL, NO_DIRECTORY)) {
SetDParamStr(0, GetSaveLoadErrorString());
ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
} else {
- if (_saveload_mode == SLD_LOAD_SCENARIO) {
+ if (_file_to_saveload.abstract_ftype == FT_SCENARIO) {
/* Reset engine pool to simplify changing engine NewGRFs in scenario editor. */
EngineOverrideManager::ResetToCurrentNewGRFConfig();
}
@@ -1134,7 +1155,7 @@ void SwitchToMode(SwitchMode new_mode)
break;
case SM_LOAD_SCENARIO: { // Load scenario from scenario editor
- if (SafeLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_EDITOR, NO_DIRECTORY)) {
+ if (SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_EDITOR, NO_DIRECTORY)) {
SetLocalCompany(OWNER_NONE);
_settings_newgame.game_creation.starting_year = _cur_year;
/* Cancel the saveload pausing */
@@ -1156,7 +1177,7 @@ void SwitchToMode(SwitchMode new_mode)
case SM_SAVE_GAME: // Save game.
/* Make network saved games on pause compatible to singleplayer */
- if (SaveOrLoad(_file_to_saveload.name, SL_SAVE, NO_DIRECTORY) != SL_OK) {
+ if (SaveOrLoad(_file_to_saveload.name, SLO_SAVE, DFT_GAME_FILE, NO_DIRECTORY) != SL_OK) {
SetDParamStr(0, GetSaveLoadErrorString());
ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
} else {
@@ -1367,7 +1388,7 @@ void StateGameLoop()
/* Save the desync savegame if needed. */
char name[MAX_PATH];
seprintf(name, lastof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
- SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR, false);
+ SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false);
}
CheckCaches();
@@ -1424,7 +1445,7 @@ static void DoAutosave()
}
DEBUG(sl, 2, "Autosaving to '%s'", buf);
- if (SaveOrLoad(buf, SL_SAVE, AUTOSAVE_DIR) != SL_OK) {
+ if (SaveOrLoad(buf, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR) != SL_OK) {
ShowErrorMessage(STR_ERROR_AUTOSAVE_FAILED, INVALID_STRING_ID, WL_ERROR);
}
}
diff --git a/src/os/os2/os2.cpp b/src/os/os2/os2.cpp
index 386cc4dbb7..7b34f528a6 100644
--- a/src/os/os2/os2.cpp
+++ b/src/os/os2/os2.cpp
@@ -45,7 +45,7 @@ bool FiosIsRoot(const char *file)
return file[3] == '\0';
}
-void FiosGetDrives()
+void FiosGetDrives(FileList &file_list)
{
uint disk, disk2, save, total;
@@ -75,7 +75,7 @@ void FiosGetDrives()
#endif
if (disk == disk2) {
- FiosItem *fios = _fios_items.Append();
+ FiosItem *fios = file_list.Append();
fios->type = FIOS_TYPE_DRIVE;
fios->mtime = 0;
#ifndef __INNOTEK_LIBC__
diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp
index 24dedb2ee1..d7c2304ce5 100644
--- a/src/os/unix/unix.cpp
+++ b/src/os/unix/unix.cpp
@@ -16,6 +16,7 @@
#include "../../core/random_func.hpp"
#include "../../debug.h"
#include "../../string_func.h"
+#include "../../fios.h"
#include
@@ -77,7 +78,7 @@ bool FiosIsRoot(const char *path)
#endif
}
-void FiosGetDrives()
+void FiosGetDrives(FileList &file_list)
{
return;
}
diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp
index 041468a139..344d243143 100644
--- a/src/os/windows/win32.cpp
+++ b/src/os/windows/win32.cpp
@@ -208,11 +208,11 @@ bool FiosIsRoot(const char *file)
return file[3] == '\0'; // C:\...
}
-void FiosGetDrives()
+void FiosGetDrives(FileList &file_list)
{
#if defined(WINCE)
/* WinCE only knows one drive: / */
- FiosItem *fios = _fios_items.Append();
+ FiosItem *fios = file_list.Append();
fios->type = FIOS_TYPE_DRIVE;
fios->mtime = 0;
seprintf(fios->name, lastof(fios->name), PATHSEP "");
@@ -223,7 +223,7 @@ void FiosGetDrives()
GetLogicalDriveStrings(lengthof(drives), drives);
for (s = drives; *s != '\0';) {
- FiosItem *fios = _fios_items.Append();
+ FiosItem *fios = file_list.Append();
fios->type = FIOS_TYPE_DRIVE;
fios->mtime = 0;
seprintf(fios->name, lastof(fios->name), "%c:", s[0] & 0xFF);
diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp
index 9690481154..de3f7ccff9 100644
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -248,7 +248,7 @@ static void InitializeWindowsAndCaches()
/* For each company, verify (while loading a scenario) that the inauguration date is the current year and set it
* accordingly if it is not the case. No need to set it on companies that are not been used already,
* thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */
- if (_file_to_saveload.filetype == FT_SCENARIO && c->inaugurated_year != MIN_YEAR) {
+ if (_file_to_saveload.abstract_ftype == FT_SCENARIO && c->inaugurated_year != MIN_YEAR) {
c->inaugurated_year = _cur_year;
}
}
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index c422cb1047..b5e88dc791 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -271,6 +271,7 @@ extern const uint16 SAVEGAME_VERSION = 195; ///< Current savegame version of Ope
const uint16 SAVEGAME_VERSION_EXT = 0x8000; ///< Savegame extension indicator mask
SavegameType _savegame_type; ///< type of savegame we are loading
+FileToSaveLoad _file_to_saveload; ///< File to save or load in the openttd loop.
uint32 _ttdp_version; ///< version of TTDP savegame (if applicable)
uint16 _sl_version; ///< the major savegame version identifier
@@ -2868,10 +2869,10 @@ SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
* @param threaded True when threaded saving is allowed
* @return Return the result of the action. #SL_OK, #SL_ERROR, or #SL_REINIT ("unload" the game)
*/
-SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
+SaveOrLoadResult SaveOrLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded)
{
/* An instance of saving is already active, so don't go saving again */
- if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
+ if (_sl.saveinprogress && fop == SLO_SAVE && dft == DFT_GAME_FILE && threaded) {
/* if not an autosave, but a user action, show error message */
if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
return SL_OK;
@@ -2880,7 +2881,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
try {
/* Load a TTDLX or TTDPatch game */
- if (mode == SL_OLD_LOAD) {
+ if (fop == SLO_LOAD && dft == DFT_OLD_GAME_FILE) {
InitializeGame(256, 256, true, true); // set a mapsize of 256x256 for TTDPatch games or it might get confused
/* TTD/TTO savegames have no NewGRFs, TTDP savegame have them
@@ -2903,25 +2904,35 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
return SL_OK;
}
- switch (mode) {
- case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
- case SL_LOAD: _sl.action = SLA_LOAD; break;
- case SL_SAVE: _sl.action = SLA_SAVE; break;
+ assert(dft == DFT_GAME_FILE);
+ switch (fop) {
+ case SLO_CHECK:
+ _sl.action = SLA_LOAD_CHECK;
+ break;
+
+ case SLO_LOAD:
+ _sl.action = SLA_LOAD;
+ break;
+
+ case SLO_SAVE:
+ _sl.action = SLA_SAVE;
+ break;
+
default: NOT_REACHED();
}
- FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
+ FILE *fh = (fop == SLO_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
/* Make it a little easier to load savegames from the console */
- if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
- if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
- if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
+ if (fh == NULL && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
+ if (fh == NULL && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
+ if (fh == NULL && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
if (fh == NULL) {
- SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
+ SlError(fop == SLO_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
}
- if (mode == SL_SAVE) { // SAVE game
+ if (fop == SLO_SAVE) { // SAVE game
DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
@@ -2929,24 +2940,25 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
}
/* LOAD game */
- assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
+ assert(fop == SLO_LOAD || fop == SLO_CHECK);
DEBUG(desync, 1, "load: %s", filename);
- return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
+ return DoLoad(new FileReader(fh), fop == SLO_CHECK);
} catch (...) {
+ /* This code may be executed both for old and new save games. */
ClearSaveLoadState();
/* Skip the "colour" character */
- if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
+ if (fop != SLO_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
/* A saver/loader exception!! reinitialize all variables to prevent crash! */
- return (mode == SL_LOAD || mode == SL_OLD_LOAD) ? SL_REINIT : SL_ERROR;
+ return (fop == SLO_LOAD) ? SL_REINIT : SL_ERROR;
}
}
/** Do a save when exiting the game (_settings_client.gui.autosave_on_exit) */
void DoExitSave()
{
- SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
+ SaveOrLoad("exit.sav", SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR);
}
/**
@@ -2984,6 +2996,53 @@ void GenerateDefaultSaveName(char *buf, const char *last)
SanitizeFilename(buf);
}
+/**
+ * Set the mode and file type of the file to save or load based on the type of file entry at the file system.
+ * @param ft Type of file entry of the file system.
+ */
+void FileToSaveLoad::SetMode(FiosType ft)
+{
+ this->SetMode(SLO_LOAD, GetAbstractFileType(ft), GetDetailedFileType(ft));
+}
+
+/**
+ * Set the mode and file type of the file to save or load.
+ * @param fop File operation being performed.
+ * @param aft Abstract file type.
+ * @param dft Detailed file type.
+ */
+void FileToSaveLoad::SetMode(SaveLoadOperation fop, AbstractFileType aft, DetailedFileType dft)
+{
+ if (aft == FT_INVALID || aft == FT_NONE) {
+ this->file_op = SLO_INVALID;
+ this->detail_ftype = DFT_INVALID;
+ this->abstract_ftype = FT_INVALID;
+ return;
+ }
+
+ this->file_op = fop;
+ this->detail_ftype = dft;
+ this->abstract_ftype = aft;
+}
+
+/**
+ * Set the name of the file.
+ * @param name Name of the file.
+ */
+void FileToSaveLoad::SetName(const char *name)
+{
+ strecpy(this->name, name, lastof(this->name));
+}
+
+/**
+ * Set the title of the file.
+ * @param title Title of the file.
+ */
+void FileToSaveLoad::SetTitle(const char *title)
+{
+ strecpy(this->title, title, lastof(this->title));
+}
+
#if 0
/**
* Function to get the type of the savegame by looking at the file header.
diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h
index 8df011958b..42bc82c48f 100644
--- a/src/saveload/saveload.h
+++ b/src/saveload/saveload.h
@@ -25,15 +25,18 @@ enum SaveOrLoadResult {
SL_REINIT = 2, ///< error that was caught in the middle of updating game state, need to clear it. (can only happen during load)
};
-/** Save or load mode. @see SaveOrLoad */
-enum SaveOrLoadMode {
- SL_INVALID = -1, ///< Invalid mode.
- SL_LOAD = 0, ///< Load game.
- SL_SAVE = 1, ///< Save game.
- SL_OLD_LOAD = 2, ///< Load old game.
- SL_PNG = 3, ///< Load PNG file (height map).
- SL_BMP = 4, ///< Load BMP file (height map).
- SL_LOAD_CHECK = 5, ///< Load for game preview.
+/** Deals with the type of the savegame, independent of extension */
+struct FileToSaveLoad {
+ SaveLoadOperation file_op; ///< File operation to perform.
+ DetailedFileType detail_ftype; ///< Concrete file type (PNG, BMP, old save, etc).
+ AbstractFileType abstract_ftype; ///< Abstract type of file (scenario, heightmap, etc).
+ char name[MAX_PATH]; ///< Name of the file.
+ char title[255]; ///< Internal name of the game.
+
+ void SetMode(FiosType ft);
+ void SetMode(SaveLoadOperation fop, AbstractFileType aft, DetailedFileType dft);
+ void SetName(const char *name);
+ void SetTitle(const char *title);
};
/** Types of save games. */
@@ -46,10 +49,12 @@ enum SavegameType {
SGT_INVALID = 0xFF, ///< broken savegame (used internally)
};
+extern FileToSaveLoad _file_to_saveload;
+
void GenerateDefaultSaveName(char *buf, const char *last);
void SetSaveLoadError(uint16 str);
const char *GetSaveLoadErrorString();
-SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded = true);
+SaveOrLoadResult SaveOrLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded = true);
void WaitTillSaved();
void ProcessAsyncSaveFinish();
void DoExitSave();
diff --git a/src/saveload/signs_sl.cpp b/src/saveload/signs_sl.cpp
index d5bacd509c..132ac181e4 100644
--- a/src/saveload/signs_sl.cpp
+++ b/src/saveload/signs_sl.cpp
@@ -60,7 +60,7 @@ static void Load_SIGN()
}
/* Signs placed in scenario editor shall now be OWNER_DEITY */
- if (IsSavegameVersionBefore(171) && si->owner == OWNER_NONE && _saveload_mode == SLD_LOAD_SCENARIO) {
+ if (IsSavegameVersionBefore(171) && si->owner == OWNER_NONE && _file_to_saveload.abstract_ftype == FT_SCENARIO) {
si->owner = OWNER_DEITY;
}
}
diff --git a/src/scope.h b/src/scope.h
new file mode 100644
index 0000000000..d341b50b1f
--- /dev/null
+++ b/src/scope.h
@@ -0,0 +1,53 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+/** @file scope.h Simple scope guard... */
+
+#ifndef SCOPE_H
+#define SCOPE_H
+
+template
+class scope_exit_obj {
+ T f;
+ bool shouldexec;
+
+
+ public:
+
+ scope_exit_obj(T &&func)
+ : f(std::move(func)), shouldexec(true) { }
+
+ scope_exit_obj(const scope_exit_obj ©src) = delete;
+ scope_exit_obj(scope_exit_obj &&movesrc)
+ : f(std::move(movesrc.f)), shouldexec(movesrc.shouldexec) {
+ movesrc.shouldexec = false;
+ }
+
+ ~scope_exit_obj() {
+ exec();
+ }
+
+ void exec() {
+ if (shouldexec) {
+ f();
+ shouldexec = false;
+ }
+ }
+
+ void cancel() {
+ shouldexec = false;
+ }
+};
+
+template
+scope_exit_obj::type> scope_guard(T &&func) {
+ return scope_exit_obj::type>(std::forward(func));
+}
+
+#endif /* SCOPE_H */
diff --git a/src/stdafx.h b/src/stdafx.h
index 4616212f18..631f64cca7 100644
--- a/src/stdafx.h
+++ b/src/stdafx.h
@@ -361,21 +361,8 @@ typedef unsigned char byte;
#define PERSONAL_DIR ""
#endif
-/* Compile time assertions. Prefer c++0x static_assert().
- * Older compilers cannot evaluate some expressions at compile time,
- * typically when templates are involved, try assert_tcompile() in those cases. */
-#if defined(__STDCXX_VERSION__) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) || defined(static_assert)
- /* __STDCXX_VERSION__ is c++0x feature macro, __GXX_EXPERIMENTAL_CXX0X__ is used by gcc, __GXX_EXPERIMENTAL_CPP0X__ by icc */
- #define assert_compile(expr) static_assert(expr, #expr )
- #define assert_tcompile(expr) assert_compile(expr)
-#elif defined(__OS2__)
- /* Disabled for OS/2 */
- #define assert_compile(expr)
- #define assert_tcompile(expr) assert_compile(expr)
-#else
- #define assert_compile(expr) typedef int __ct_assert__[1 - 2 * !(expr)]
- #define assert_tcompile(expr) assert(expr)
-#endif
+#define assert_compile(expr) static_assert(expr, #expr )
+#define assert_tcompile(expr) assert_compile(expr)
/* Check if the types have the bitsizes like we are using them */
assert_compile(sizeof(uint64) == 8);
@@ -444,8 +431,17 @@ assert_compile(SIZE_MAX >= UINT32_MAX);
#define CloseConnection OTTD_CloseConnection
#endif /* __APPLE__ */
+#ifdef __GNUC__
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
void NORETURN CDECL usererror(const char *str, ...) WARN_FORMAT(1, 2);
void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2);
+void NORETURN CDECL assert_msg_error(int line, const char *file, const char *expr, const char *str, ...) WARN_FORMAT(4, 5);
#define NOT_REACHED() error("NOT_REACHED triggered at line %i of %s", __LINE__, __FILE__)
/* For non-debug builds with assertions enabled use the special assertion handler:
@@ -454,12 +450,15 @@ void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2);
*/
#if (defined(_MSC_VER) && defined(NDEBUG) && defined(WITH_ASSERT)) || (!defined(_MSC_VER) && !defined(NDEBUG) && !defined(_DEBUG))
#undef assert
- #define assert(expression) if (!(expression)) error("Assertion failed at line %i of %s: %s", __LINE__, __FILE__, #expression);
+ #define assert(expression) if (unlikely(!(expression))) error("Assertion failed at line %i of %s: %s", __LINE__, __FILE__, #expression);
#endif
/* Asserts are enabled if NDEBUG isn't defined, or if we are using MSVC and WITH_ASSERT is defined. */
#if !defined(NDEBUG) || (defined(_MSC_VER) && defined(WITH_ASSERT))
#define OTTD_ASSERT
+ #define assert_msg(expression, ...) if (unlikely(!(expression))) assert_msg_error(__LINE__, __FILE__, #expression, __VA_ARGS__);
+#else
+ #define assert_msg(expression, ...)
#endif
#if defined(MORPHOS) || defined(__NDS__) || defined(__DJGPP__)
diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h
index b7d0c92024..afe19bbedb 100644
--- a/src/table/newgrf_debug_data.h
+++ b/src/table/newgrf_debug_data.h
@@ -17,7 +17,7 @@
#define NIP_END() { NULL, 0, 0, 0, 0 }
/* Helper for filling callback tables */
-#define NIC(cb_id, base, variable, bit) { #cb_id, cpp_offsetof(base, variable), cpp_sizeof(base, variable), bit, cb_id }
+#define NIC(cb_id, base, variable, bit) { #cb_id, (ptrdiff_t)cpp_offsetof(base, variable), cpp_sizeof(base, variable), bit, cb_id }
#define NIC_END() { NULL, 0, 0, 0, 0 }
/* Helper for filling variable tables */
diff --git a/src/table/townname.h b/src/table/townname.h
index 25c997d255..d14999340c 100644
--- a/src/table/townname.h
+++ b/src/table/townname.h
@@ -11,6 +11,10 @@
#include "../core/enum_type.hpp"
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#endif
+
static const char * const _name_original_english_1[] = {
"Great ",
"Little ",
diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp
index 40c75ad710..2649552f45 100644
--- a/src/toolbar_gui.cpp
+++ b/src/toolbar_gui.cpp
@@ -427,17 +427,17 @@ static CallBackFunction MenuClickSaveLoad(int index = 0)
{
if (_game_mode == GM_EDITOR) {
switch (index) {
- case SLEME_SAVE_SCENARIO: ShowSaveLoadDialog(SLD_SAVE_SCENARIO); break;
- case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
- case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(SLD_SAVE_HEIGHTMAP); break;
- case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
+ case SLEME_SAVE_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_SAVE); break;
+ case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_LOAD); break;
+ case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_SAVE); break;
+ case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_LOAD); break;
case SLEME_EXIT_TOINTRO: AskExitToGameMenu(); break;
case SLEME_EXIT_GAME: HandleExitGameRequest(); break;
}
} else {
switch (index) {
- case SLNME_SAVE_GAME: ShowSaveLoadDialog(SLD_SAVE_GAME); break;
- case SLNME_LOAD_GAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
+ case SLNME_SAVE_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_SAVE); break;
+ case SLNME_LOAD_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
case SLNME_EXIT_TOINTRO: AskExitToGameMenu(); break;
case SLNME_EXIT_GAME: HandleExitGameRequest(); break;
}
@@ -1712,7 +1712,7 @@ struct MainToolbarWindow : Window {
case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
case MTHK_SETTINGS: ShowGameOptions(); break;
case MTHK_SAVEGAME: MenuClickSaveLoad(); break;
- case MTHK_LOADGAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
+ case MTHK_LOADGAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
case MTHK_SMALLMAP: ShowSmallMap(); break;
case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break;
case MTHK_SUBSIDIES: ShowSubsidiesList(); break;
diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp
index bfe853e9a0..e038df9751 100644
--- a/src/video/dedicated_v.cpp
+++ b/src/video/dedicated_v.cpp
@@ -142,7 +142,7 @@ static void *_dedicated_video_mem;
/* Whether a fork has been done. */
bool _dedicated_forks;
-extern bool SafeLoad(const char *filename, int mode, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL);
+extern bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL);
static FVideoDriver_Dedicated iFVideoDriver_Dedicated;
@@ -286,7 +286,7 @@ void VideoDriver_Dedicated::MainLoop()
_switch_mode = SM_NONE;
/* First we need to test if the savegame can be loaded, else we will end up playing the
* intro game... */
- if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL, BASE_DIR)) {
+ if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_NORMAL, BASE_DIR)) {
/* Loading failed, pop out.. */
DEBUG(net, 0, "Loading requested map failed, aborting");
_networking = false;