Procházet zdrojové kódy

Merge branch 'develop' of github.com:karol57/vcmi into karol57-develop

Ivan Savenko před 11 roky
rodič
revize
de9c5b1af7
49 změnil soubory, kde provedl 1126 přidání a 853 odebrání
  1. 1 1
      AI/BattleAI/main.cpp
  2. 1 1
      AI/StupidAI/main.cpp
  3. 1 1
      AI/VCAI/main.cpp
  4. 2 0
      ChangeLog
  5. 58 22
      Global.h
  6. 40 45
      client/CMT.cpp
  7. 4 13
      client/CPlayerInterface.cpp
  8. 1 1
      client/CVideoHandler.cpp
  9. 1 2
      client/CVideoHandler.h
  10. 10 9
      client/Client.cpp
  11. 1 1
      editor/Editor.cpp
  12. 10 1
      launcher/StdInc.h
  13. 2 2
      launcher/launcherdirs.cpp
  14. 4 4
      launcher/mainwindow_moc.cpp
  15. 1 1
      launcher/modManager/cmodmanager.cpp
  16. 3 3
      launcher/settingsView/csettingsview_moc.cpp
  17. 6 17
      lib/BattleHex.cpp
  18. 15 28
      lib/BattleHex.h
  19. 17 7
      lib/CConsoleHandler.cpp
  20. 2 2
      lib/CConsoleHandler.h
  21. 35 32
      lib/CGameInterface.cpp
  22. 3 3
      lib/CThreadHelper.cpp
  23. 15 17
      lib/CondSh.h
  24. 9 9
      lib/Connection.cpp
  25. 4 4
      lib/Connection.h
  26. 478 153
      lib/VCMIDirs.cpp
  27. 44 38
      lib/VCMIDirs.h
  28. 10 19
      lib/filesystem/CArchiveLoader.cpp
  29. 2 2
      lib/filesystem/CArchiveLoader.h
  30. 15 14
      lib/filesystem/CFileInfo.cpp
  31. 4 6
      lib/filesystem/CFileInputStream.cpp
  32. 3 3
      lib/filesystem/CFileInputStream.h
  33. 56 30
      lib/filesystem/CFilesystemLoader.cpp
  34. 5 5
      lib/filesystem/CFilesystemLoader.h
  35. 2 2
      lib/filesystem/Filesystem.cpp
  36. 8 6
      lib/int3.h
  37. 8 16
      lib/logging/CBasicLogConfigurator.cpp
  38. 9 6
      lib/logging/CBasicLogConfigurator.h
  39. 93 221
      lib/logging/CLogger.cpp
  40. 36 30
      lib/logging/CLogger.h
  41. 1 1
      lib/mapObjects/CArmedInstance.h
  42. 1 1
      lib/mapObjects/CBank.h
  43. 1 1
      lib/mapObjects/CGHeroInstance.h
  44. 1 1
      lib/mapObjects/CGPandoraBox.h
  45. 1 1
      lib/mapObjects/CObjectHandler.h
  46. 87 56
      lib/rmg/float3.h
  47. 6 6
      scripting/erm/ERMInterpreter.cpp
  48. 8 8
      server/CVCMIServer.cpp
  49. 1 1
      test/CVcmiTestConfig.cpp

+ 1 - 1
AI/BattleAI/main.cpp

@@ -7,7 +7,7 @@
 #define strcpy_s(a, b, c) strncpy(a, c, b)
 #define strcpy_s(a, b, c) strncpy(a, c, b)
 #endif
 #endif
 
 
-#ifdef __ANDROID__
+#ifdef VCMI_ANDROID
 #define GetGlobalAiVersion BattleAI_GetGlobalAiVersion
 #define GetGlobalAiVersion BattleAI_GetGlobalAiVersion
 #define GetAiName BattleAI_GetAiName
 #define GetAiName BattleAI_GetAiName
 #define GetNewBattleAI BattleAI_GetNewBattleAI
 #define GetNewBattleAI BattleAI_GetNewBattleAI

+ 1 - 1
AI/StupidAI/main.cpp

@@ -7,7 +7,7 @@
 #define strcpy_s(a, b, c) strncpy(a, c, b)
 #define strcpy_s(a, b, c) strncpy(a, c, b)
 #endif
 #endif
 
 
-#ifdef __ANDROID__
+#ifdef VCMI_ANDROID
 #define GetGlobalAiVersion StupidAI_GetGlobalAiVersion
 #define GetGlobalAiVersion StupidAI_GetGlobalAiVersion
 #define GetAiName StupidAI_GetAiName
 #define GetAiName StupidAI_GetAiName
 #define GetNewBattleAI StupidAI_GetNewBattleAI
 #define GetNewBattleAI StupidAI_GetNewBattleAI

+ 1 - 1
AI/VCAI/main.cpp

@@ -5,7 +5,7 @@
 #define strcpy_s(a, b, c) strncpy(a, c, b)
 #define strcpy_s(a, b, c) strncpy(a, c, b)
 #endif
 #endif
 
 
-#ifdef __ANDROID__
+#ifdef VCMI_ANDROID
 #define GetGlobalAiVersion VCAI_GetGlobalAiVersion
 #define GetGlobalAiVersion VCAI_GetGlobalAiVersion
 #define GetAiName VCAI_GetAiName
 #define GetAiName VCAI_GetAiName
 #define GetNewAI VCAI_GetNewAI
 #define GetNewAI VCAI_GetNewAI

+ 2 - 0
ChangeLog

@@ -3,6 +3,8 @@ GENERAL:
 * VCMI can now be compiled with SDL2
 * VCMI can now be compiled with SDL2
 * Better upscaling when running in fullscreen mode.
 * Better upscaling when running in fullscreen mode.
 * Non-latin characters can now be entered in chat window or used for save names.
 * Non-latin characters can now be entered in chat window or used for save names.
+* (windows) Moved VCMI data directory from '%userprofile%\vcmi' to '%userprofile%\Documents\My Games\vcmi'
+* (windows, OSX) Moved VCMI save directory from 'VCMI_DATA\Games' to 'VCMI_DATA\Saves'
 
 
 RANDOM MAP GENERATOR:
 RANDOM MAP GENERATOR:
 
 

+ 58 - 22
Global.h

@@ -49,10 +49,58 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #  pragma warning (disable : 4800 ) /* disable conversion to bool warning -- I think it's intended in all places */
 #  pragma warning (disable : 4800 ) /* disable conversion to bool warning -- I think it's intended in all places */
 #endif
 #endif
 
 
+/* ---------------------------------------------------------------------------- */
+/* System detection. */
+/* ---------------------------------------------------------------------------- */
+// Based on: http://sourceforge.net/p/predef/wiki/OperatingSystems/
+//	 and on: http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
+// TODO?: Should be moved to vstd\os_detect.h (and then included by Global.h)
+#ifdef _WIN16			// Defined for 16-bit environments
+#  error "16-bit Windows isn't supported"
+#elif defined(_WIN64)	// Defined for 64-bit environments
+#  define VCMI_WINDOWS
+#  define VCMI_WINDOWS_64
+#elif defined(_WIN32)	// Defined for both 32-bit and 64-bit environments
+#  define VCMI_WINDOWS
+#  define VCMI_WINDOWS_32
+#elif defined(_WIN32_WCE)
+#  error "Windows CE isn't supported"
+#elif defined(__linux__) || defined(__gnu_linux__) || defined(linux) || defined(__linux)
+#  define VCMI_UNIX
+#  define VCMI_LINUX
+#  ifdef __ANDROID__
+#    define VCMI_ANDROID 
+#  endif
+#elif defined(__APPLE__) && defined(__MACH__)
+#  define VCMI_UNIX
+#  define VCMI_APPLE
+#  include "TargetConditionals.h"
+#  if TARGET_IPHONE_SIMULATOR
+#    define VCMI_IOS
+#    define VCMI_IOS_SIM
+#  elif TARGET_OS_IPHONE
+#    define VCMI_IOS
+#  elif TARGET_OS_MAC
+#    define VCMI_MAC
+#  else
+//#  warning "Unknown Apple target."?
+#  endif
+#else
+#  error "VCMI supports only Windows, OSX, Linux and Android targets"
+#endif
+
+#ifdef VCMI_IOS
+#  error "iOS system isn't yet supported."
+#endif
+
 /* ---------------------------------------------------------------------------- */
 /* ---------------------------------------------------------------------------- */
 /* Commonly used C++, Boost headers */
 /* Commonly used C++, Boost headers */
 /* ---------------------------------------------------------------------------- */
 /* ---------------------------------------------------------------------------- */
-#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
+#ifdef VCMI_WINDOWS
+#  define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers - delete this line if something is missing.
+#  define NOMINMAX					// Exclude min/max macros from <Windows.h>. Use std::[min/max] from <algorithm> instead.
+#endif
+
 #define _USE_MATH_DEFINES
 #define _USE_MATH_DEFINES
 
 
 #include <cstdio>
 #include <cstdio>
@@ -86,7 +134,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 
 
 #define BOOST_FILESYSTEM_VERSION 3
 #define BOOST_FILESYSTEM_VERSION 3
 #if BOOST_VERSION > 105000
 #if BOOST_VERSION > 105000
-#define BOOST_THREAD_VERSION 3
+#  define BOOST_THREAD_VERSION 3
 #endif
 #endif
 #define BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE 1
 #define BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE 1
 #define BOOST_BIND_NO_PLACEHOLDERS
 #define BOOST_BIND_NO_PLACEHOLDERS
@@ -99,9 +147,12 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/date_time/posix_time/posix_time_io.hpp>
 #include <boost/date_time/posix_time/posix_time_io.hpp>
 #include <boost/filesystem.hpp>
 #include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/fstream.hpp>
 #include <boost/format.hpp>
 #include <boost/format.hpp>
 #include <boost/functional/hash.hpp>
 #include <boost/functional/hash.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/lexical_cast.hpp>
+#include <boost/locale/generator.hpp>
 #include <boost/logic/tribool.hpp>
 #include <boost/logic/tribool.hpp>
 #include <boost/optional.hpp>
 #include <boost/optional.hpp>
 #include <boost/program_options.hpp>
 #include <boost/program_options.hpp>
@@ -112,13 +163,8 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #include <boost/variant.hpp>
 #include <boost/variant.hpp>
 #include <boost/math/special_functions/round.hpp>
 #include <boost/math/special_functions/round.hpp>
 
 
-
-#ifdef ANDROID
-#include <android/log.h>
-#endif
-
 #ifndef M_PI
 #ifndef M_PI
-#define M_PI 3.14159265358979323846
+#  define M_PI 3.14159265358979323846
 #endif
 #endif
 
 
 /* ---------------------------------------------------------------------------- */
 /* ---------------------------------------------------------------------------- */
@@ -151,30 +197,20 @@ typedef boost::lock_guard<boost::recursive_mutex> TLockGuardRec;
 /* Macros */
 /* Macros */
 /* ---------------------------------------------------------------------------- */
 /* ---------------------------------------------------------------------------- */
 // Import + Export macro declarations
 // Import + Export macro declarations
-#ifdef _WIN32
+#ifdef VCMI_WINDOWS
 #  ifdef __GNUC__
 #  ifdef __GNUC__
+#    define DLL_IMPORT __attribute__((dllimport))
 #    define DLL_EXPORT __attribute__((dllexport))
 #    define DLL_EXPORT __attribute__((dllexport))
 #  else
 #  else
+#    define DLL_IMPORT __declspec(dllimport)
 #    define DLL_EXPORT __declspec(dllexport)
 #    define DLL_EXPORT __declspec(dllexport)
 #  endif
 #  endif
 #  define ELF_VISIBILITY
 #  define ELF_VISIBILITY
 #else
 #else
 #  ifdef __GNUC__
 #  ifdef __GNUC__
+#    define DLL_IMPORT	__attribute__ ((visibility("default")))
 #    define DLL_EXPORT __attribute__ ((visibility("default")))
 #    define DLL_EXPORT __attribute__ ((visibility("default")))
 #    define ELF_VISIBILITY __attribute__ ((visibility("default")))
 #    define ELF_VISIBILITY __attribute__ ((visibility("default")))
-#  endif
-#endif
-
-#ifdef _WIN32
-#  ifdef __GNUC__
-#    define DLL_IMPORT __attribute__((dllimport))
-#  else
-#    define DLL_IMPORT __declspec(dllimport)
-#  endif
-#  define ELF_VISIBILITY
-#else
-#  ifdef __GNUC__
-#    define DLL_IMPORT	__attribute__ ((visibility("default")))
 #    define ELF_VISIBILITY __attribute__ ((visibility("default")))
 #    define ELF_VISIBILITY __attribute__ ((visibility("default")))
 #  endif
 #  endif
 #endif
 #endif

+ 40 - 45
client/CMT.cpp

@@ -41,7 +41,7 @@
 #include "../lib/logging/CBasicLogConfigurator.h"
 #include "../lib/logging/CBasicLogConfigurator.h"
 #include "../lib/CondSh.h"
 #include "../lib/CondSh.h"
 
 
-#ifdef _WIN32
+#ifdef VCMI_WINDOWS
 #include "SDL_syswm.h"
 #include "SDL_syswm.h"
 #endif
 #endif
 #include "../lib/UnlockGuard.h"
 #include "../lib/UnlockGuard.h"
@@ -52,6 +52,7 @@
 #endif
 #endif
 
 
 namespace po = boost::program_options;
 namespace po = boost::program_options;
+namespace bfs = boost::filesystem;
 
 
 /*
 /*
  * CMT.cpp, part of VCMI engine
  * CMT.cpp, part of VCMI engine
@@ -73,13 +74,12 @@ int preferredDriverIndex = -1;
 SDL_Window * mainWindow = nullptr;
 SDL_Window * mainWindow = nullptr;
 SDL_Renderer * mainRenderer = nullptr;
 SDL_Renderer * mainRenderer = nullptr;
 SDL_Texture * screenTexture = nullptr;
 SDL_Texture * screenTexture = nullptr;
-
 #endif // VCMI_SDL1
 #endif // VCMI_SDL1
 
 
 extern boost::thread_specific_ptr<bool> inGuiThread;
 extern boost::thread_specific_ptr<bool> inGuiThread;
 
 
 SDL_Surface *screen = nullptr, //main screen surface
 SDL_Surface *screen = nullptr, //main screen surface
-	*screen2 = nullptr,//and hlp surface (used to store not-active interfaces layer)
+	*screen2 = nullptr, //and hlp surface (used to store not-active interfaces layer)
 	*screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
 	*screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
 	
 	
 std::queue<SDL_Event> events;
 std::queue<SDL_Event> events;
@@ -100,31 +100,29 @@ static void mainLoop();
 void startGame(StartInfo * options, CConnection *serv = nullptr);
 void startGame(StartInfo * options, CConnection *serv = nullptr);
 void endGame();
 void endGame();
 
 
-#ifndef _WIN32
+#ifndef VCMI_WINDOWS
 #ifndef _GNU_SOURCE
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
 #endif
 #include <getopt.h>
 #include <getopt.h>
 #endif
 #endif
 
 
-void startGameFromFile(const std::string &fname)
+void startGameFromFile(const bfs::path &fname)
 {
 {
 	StartInfo si;
 	StartInfo si;
 	try //attempt retrieving start info from given file
 	try //attempt retrieving start info from given file
 	{
 	{
-		if(!fname.size() || !boost::filesystem::exists(fname))
-			throw std::runtime_error("Startfile \"" + fname + "\" does not exist!");
+		if(fname.empty() || !bfs::exists(fname))
+			throw std::runtime_error("Startfile \"" + fname.string() + "\" does not exist!");
 
 
 		CLoadFile out(fname);
 		CLoadFile out(fname);
-		if(!out.sfile || !*out.sfile)
-		{
-			throw std::runtime_error("Cannot read from startfile \"" + fname + "\"!");
-		}
+		if (!out.sfile || !*out.sfile)
+			throw std::runtime_error("Cannot read from startfile \"" + fname.string() +"\"!");
 		out >> si;
 		out >> si;
 	}
 	}
 	catch(std::exception &e)
 	catch(std::exception &e)
 	{
 	{
-		logGlobal->errorStream() << "Failed to start from the file: " + fname << ". Error: " << e.what()
+		logGlobal->errorStream() << "Failed to start from the file: " << fname << ". Error: " << e.what()
 			<< " Falling back to main menu.";
 			<< " Falling back to main menu.";
 		GH.curInt = CGPreGame::create();
 		GH.curInt = CGPreGame::create();
 		return;
 		return;
@@ -184,19 +182,19 @@ static void prog_help(const po::options_description &opts)
 // 	printf("  -v, --version     display version information and exit\n");
 // 	printf("  -v, --version     display version information and exit\n");
 }
 }
 
 
-#ifdef __APPLE__
+#ifdef VCMI_APPLE
 void OSX_checkForUpdates();
 void OSX_checkForUpdates();
 #endif
 #endif
 
 
-#if defined(_WIN32) && !defined (__GNUC__)
+#if defined(VCMI_WINDOWS) && !defined (__GNUC__)
 int wmain(int argc, wchar_t* argv[])
 int wmain(int argc, wchar_t* argv[])
-#elif defined(__APPLE__)
+#elif defined(VCMI_APPLE)
 int SDL_main(int argc, char *argv[])
 int SDL_main(int argc, char *argv[])
 #else
 #else
 int main(int argc, char** argv)
 int main(int argc, char** argv)
 #endif
 #endif
 {
 {
-#ifdef __APPLE__
+#ifdef VCMI_APPLE
 	// Correct working dir executable folder (not bundle folder) so we can use executable relative paths
 	// Correct working dir executable folder (not bundle folder) so we can use executable relative paths
     std::string executablePath = argv[0];
     std::string executablePath = argv[0];
     std::string workDir = executablePath.substr(0, executablePath.rfind('/'));
     std::string workDir = executablePath.substr(0, executablePath.rfind('/'));
@@ -206,7 +204,7 @@ int main(int argc, char** argv)
     OSX_checkForUpdates();
     OSX_checkForUpdates();
 
 
     // Check that game data is prepared. Otherwise run vcmibuilder helper application
     // Check that game data is prepared. Otherwise run vcmibuilder helper application
-    FILE* check = fopen((VCMIDirs::get().userDataPath() + "/game_data_prepared").c_str(), "r");
+    FILE* check = fopen((VCMIDirs::get().userDataPath() / "game_data_prepared").string().c_str(), "r");
     if (check == nullptr) {
     if (check == nullptr) {
         system("open ./vcmibuilder.app");
         system("open ./vcmibuilder.app");
         return 0;
         return 0;
@@ -219,7 +217,7 @@ int main(int argc, char** argv)
 		("help,h", "display help and exit")
 		("help,h", "display help and exit")
 		("version,v", "display version information and exit")
 		("version,v", "display version information and exit")
 		("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only")
 		("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only")
-		("start", po::value<std::string>(), "starts game from saved StartInfo file")
+		("start", po::value<bfs::path>(), "starts game from saved StartInfo file")
 		("onlyAI", "runs without human player, all players will be default AI")
 		("onlyAI", "runs without human player, all players will be default AI")
 		("noGUI", "runs without GUI, implies --onlyAI")
 		("noGUI", "runs without GUI, implies --onlyAI")
 		("ai", po::value<std::vector<std::string>>(), "AI to be used for the player, can be specified several times for the consecutive players")
 		("ai", po::value<std::vector<std::string>>(), "AI to be used for the player, can be specified several times for the consecutive players")
@@ -272,17 +270,17 @@ int main(int argc, char** argv)
 	CStopWatch total, pomtime;
 	CStopWatch total, pomtime;
 	std::cout.flags(std::ios::unitbuf);
 	std::cout.flags(std::ios::unitbuf);
 	console = new CConsoleHandler;
 	console = new CConsoleHandler;
-	*console->cb = std::bind(&processCommand, _1);
+	*console->cb = processCommand;
 	console->start();
 	console->start();
 	atexit(dispose);
 	atexit(dispose);
 
 
-	const auto logPath = VCMIDirs::get().userCachePath() + "/VCMI_Client_log.txt";
+	const bfs::path logPath = VCMIDirs::get().userCachePath() / "VCMI_Client_log.txt";
 	CBasicLogConfigurator logConfig(logPath, console);
 	CBasicLogConfigurator logConfig(logPath, console);
     logConfig.configureDefault();
     logConfig.configureDefault();
 	logGlobal->infoStream() << "Creating console and configuring logger: " << pomtime.getDiff();
 	logGlobal->infoStream() << "Creating console and configuring logger: " << pomtime.getDiff();
 	logGlobal->infoStream() << "The log file will be saved to " << logPath;
 	logGlobal->infoStream() << "The log file will be saved to " << logPath;
 
 
-#ifdef __ANDROID__
+#ifdef VCMI_ANDROID
 	// boost will crash without this
 	// boost will crash without this
 	setenv("LANG", "C", 1);
 	setenv("LANG", "C", 1);
 #endif
 #endif
@@ -388,7 +386,7 @@ int main(int argc, char** argv)
 
 
     logGlobal->infoStream()<<"\tInitializing video: "<<pomtime.getDiff();
     logGlobal->infoStream()<<"\tInitializing video: "<<pomtime.getDiff();
 
 
-#if defined(__ANDROID__)
+#if defined(VCMI_ANDROID)
 	//on Android threaded init is broken
 	//on Android threaded init is broken
 	#define VCMI_NO_THREADED_LOAD
 	#define VCMI_NO_THREADED_LOAD
 #endif // defined
 #endif // defined
@@ -430,15 +428,15 @@ int main(int argc, char** argv)
 		session["autoSkip"].Bool()  = vm.count("autoSkip");
 		session["autoSkip"].Bool()  = vm.count("autoSkip");
 		session["oneGoodAI"].Bool() = vm.count("oneGoodAI");
 		session["oneGoodAI"].Bool() = vm.count("oneGoodAI");
 
 
-		std::string fileToStartFrom; //none by default
+		bfs::path fileToStartFrom; //none by default
 		if(vm.count("start"))
 		if(vm.count("start"))
-			fileToStartFrom = vm["start"].as<std::string>();
+			fileToStartFrom = vm["start"].as<bfs::path>();
 
 
-		if(fileToStartFrom.size() && boost::filesystem::exists(fileToStartFrom))
+		if(!fileToStartFrom.empty() && bfs::exists(fileToStartFrom))
 			startGameFromFile(fileToStartFrom); //ommit pregame and start the game using settings from file
 			startGameFromFile(fileToStartFrom); //ommit pregame and start the game using settings from file
 		else
 		else
 		{
 		{
-			if(fileToStartFrom.size())
+			if(!fileToStartFrom.empty())
 			{
 			{
                 logGlobal->warnStream() << "Warning: cannot find given file to start from (" << fileToStartFrom
                 logGlobal->warnStream() << "Warning: cannot find given file to start from (" << fileToStartFrom
                     << "). Falling back to main menu.";
                     << "). Falling back to main menu.";
@@ -584,7 +582,8 @@ void processCommand(const std::string &message)
 	{
 	{
         std::cout<<"Command accepted.\t";
         std::cout<<"Command accepted.\t";
 
 
-		std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
+		const bfs::path outPath =
+			VCMIDirs::get().userCachePath() / "extracted";
 
 
 		auto list = CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
 		auto list = CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
 		{
 		{
@@ -593,18 +592,18 @@ void processCommand(const std::string &message)
 
 
 		for (auto & filename : list)
 		for (auto & filename : list)
 		{
 		{
-			std::string outName = outPath + filename.getName();
-
-			boost::filesystem::create_directories(outName.substr(0, outName.find_last_of("/")));
+			const bfs::path filePath = outPath / (filename.getName() + ".TXT");
+			
+			bfs::create_directories(filePath.parent_path());
 
 
-			std::ofstream file(outName + ".TXT");
+			bfs::ofstream file(filePath);
 			auto text = CResourceHandler::get()->load(filename)->readAll();
 			auto text = CResourceHandler::get()->load(filename)->readAll();
 
 
 			file.write((char*)text.first.get(), text.second);
 			file.write((char*)text.first.get(), text.second);
 		}
 		}
 
 
         std::cout << "\rExtracting done :)\n";
         std::cout << "\rExtracting done :)\n";
-        std::cout << " Extracted files can be found in " << outPath << " directory\n";
+		std::cout << " Extracted files can be found in " << outPath << " directory\n";
 	}
 	}
 	else if(cn=="crash")
 	else if(cn=="crash")
 	{
 	{
@@ -710,15 +709,13 @@ void processCommand(const std::string &message)
 		{
 		{
 			CDefEssential * cde = CDefHandler::giveDefEss(URI);
 			CDefEssential * cde = CDefHandler::giveDefEss(URI);
 
 
-			std::string outName = URI;
-			std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
-
-			boost::filesystem::create_directories(outPath + outName);
+			const bfs::path outPath = VCMIDirs::get().userCachePath() / "extracted" / URI;
+			bfs::create_directories(outPath);
 
 
-			for (size_t i=0; i<cde->ourImages.size(); i++)
+			for (size_t i = 0; i < cde->ourImages.size(); ++i)
 			{
 			{
-				std::string filename = outPath + outName + '/' + boost::lexical_cast<std::string>(i) + ".bmp";
-				SDL_SaveBMP(cde->ourImages[i].bitmap, filename.c_str());
+				const bfs::path filePath = outPath / (boost::lexical_cast<std::string>(i)+".bmp");
+				SDL_SaveBMP(cde->ourImages[i].bitmap, filePath.string().c_str());
 			}
 			}
 		}
 		}
 		else
 		else
@@ -731,14 +728,12 @@ void processCommand(const std::string &message)
 
 
 		if (CResourceHandler::get()->existsResource(ResourceID(URI)))
 		if (CResourceHandler::get()->existsResource(ResourceID(URI)))
 		{
 		{
-			std::string outName = URI;
-			std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
-			std::string fullPath = outPath + outName;
+			const bfs::path outPath = VCMIDirs::get().userCachePath() / "extracted" / URI;
 
 
 			auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
 			auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
 
 
-			boost::filesystem::create_directories(fullPath.substr(0, fullPath.find_last_of("/")));
-			std::ofstream outFile(outPath + outName, std::ofstream::binary);
+			bfs::create_directories(outPath.parent_path());
+			bfs::ofstream outFile(outPath, bfs::ofstream::binary);
 			outFile.write((char*)data.first.get(), data.second);
 			outFile.write((char*)data.first.get(), data.second);
 		}
 		}
 		else
 		else
@@ -1013,7 +1008,7 @@ static void setScreenRes(int w, int h, int bpp, bool fullscreen, bool resetVideo
 	SDL_ShowCursor(SDL_DISABLE);
 	SDL_ShowCursor(SDL_DISABLE);
 	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 
 
-#ifdef _WIN32
+#ifdef VCMI_WINDOWS
 	SDL_SysWMinfo wm;
 	SDL_SysWMinfo wm;
 	SDL_VERSION(&wm.version);
 	SDL_VERSION(&wm.version);
 	int getwm = SDL_GetWMInfo(&wm);
 	int getwm = SDL_GetWMInfo(&wm);

+ 4 - 13
client/CPlayerInterface.cpp

@@ -42,13 +42,6 @@
 #include "../lib/UnlockGuard.h"
 #include "../lib/UnlockGuard.h"
 #include <SDL.h>
 #include <SDL.h>
 
 
-#ifdef min
-#undef min
-#endif
-#ifdef max
-#undef max
-#endif
-
 /*
 /*
  * CPlayerInterface.cpp, part of VCMI engine
  * CPlayerInterface.cpp, part of VCMI engine
  *
  *
@@ -1622,22 +1615,20 @@ int CPlayerInterface::getLastIndex( std::string namePrefix)
 	path gamesDir = VCMIDirs::get().userSavePath();
 	path gamesDir = VCMIDirs::get().userSavePath();
 	std::map<std::time_t, int> dates; //save number => datestamp
 	std::map<std::time_t, int> dates; //save number => datestamp
 
 
-	directory_iterator enddir;
+	const directory_iterator enddir;
 	if(!exists(gamesDir))
 	if(!exists(gamesDir))
 		create_directory(gamesDir);
 		create_directory(gamesDir);
-
-	for (directory_iterator dir(gamesDir); dir!=enddir; dir++)
+	else
+	for (directory_iterator dir(gamesDir); dir != enddir; ++dir)
 	{
 	{
 		if(is_regular(dir->status()))
 		if(is_regular(dir->status()))
 		{
 		{
-			std::string name = dir->path().leaf().string();
+			std::string name = dir->path().filename().string();
 			if(starts_with(name, namePrefix) && ends_with(name, ".vcgm1"))
 			if(starts_with(name, namePrefix) && ends_with(name, ".vcgm1"))
 			{
 			{
 				char nr = name[namePrefix.size()];
 				char nr = name[namePrefix.size()];
 				if(std::isdigit(nr))
 				if(std::isdigit(nr))
-				{
 					dates[last_write_time(dir->path())] = boost::lexical_cast<int>(nr);
 					dates[last_write_time(dir->path())] = boost::lexical_cast<int>(nr);
-				}
 			}
 			}
 		}
 		}
 	}
 	}

+ 1 - 1
client/CVideoHandler.cpp

@@ -23,7 +23,7 @@ static bool keyDown()
 }
 }
 #endif
 #endif
 
 
-#if defined(_WIN32)  &&  (_MSC_VER < 1800 ||  !defined(USE_FFMPEG))
+#if defined(VCMI_WINDOWS)  &&  (_MSC_VER < 1800 ||  !defined(USE_FFMPEG))
 
 
 void checkForError(bool throwing = true)
 void checkForError(bool throwing = true)
 {
 {

+ 1 - 2
client/CVideoHandler.h

@@ -43,9 +43,8 @@ public:
 };
 };
 
 
 
 
-#if defined(_WIN32)  &&  (_MSC_VER < 1800 ||  !defined(USE_FFMPEG))
+#if defined(VCMI_WINDOWS)  &&  (_MSC_VER < 1800 ||  !defined(USE_FFMPEG))
 
 
-#define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
 #include <windows.h>
 #include <windows.h>
 
 
 #pragma pack(push,1)
 #pragma pack(push,1)

+ 10 - 9
client/Client.cpp

@@ -20,7 +20,7 @@
 #include "../lib/CBuildingHandler.h"
 #include "../lib/CBuildingHandler.h"
 #include "../lib/CSpellHandler.h"
 #include "../lib/CSpellHandler.h"
 #include "../lib/Connection.h"
 #include "../lib/Connection.h"
-#ifndef __ANDROID__
+#ifndef VCMI_ANDROID
 #include "../lib/Interprocess.h"
 #include "../lib/Interprocess.h"
 #endif
 #endif
 #include "../lib/NetPacks.h"
 #include "../lib/NetPacks.h"
@@ -40,7 +40,7 @@
 #include "CMT.h"
 #include "CMT.h"
 
 
 extern std::string NAME;
 extern std::string NAME;
-#ifndef __ANDROID__
+#ifndef VCMI_ANDROID
 namespace intpr = boost::interprocess;
 namespace intpr = boost::interprocess;
 #endif
 #endif
 
 
@@ -780,8 +780,9 @@ std::string CClient::aiNameForPlayer(const PlayerSettings &ps, bool battleAI)
 {
 {
 	if(ps.name.size())
 	if(ps.name.size())
 	{
 	{
-		std::string filename = VCMIDirs::get().libraryPath() + "/AI/" + VCMIDirs::get().libraryName(ps.name);
-		if(boost::filesystem::exists(filename))
+		const boost::filesystem::path aiPath =
+			VCMIDirs::get().libraryPath() / "AI" / VCMIDirs::get().libraryName(ps.name);
+		if (boost::filesystem::exists(aiPath))
 			return ps.name;
 			return ps.name;
 	}
 	}
 
 
@@ -814,7 +815,7 @@ void CServerHandler::waitForServer()
 		startServer();
 		startServer();
 
 
 	th.update();
 	th.update();
-#ifndef __ANDROID__
+#ifndef VCMI_ANDROID
 	intpr::scoped_lock<intpr::interprocess_mutex> slock(shared->sr->mutex);
 	intpr::scoped_lock<intpr::interprocess_mutex> slock(shared->sr->mutex);
 	while(!shared->sr->ready)
 	while(!shared->sr->ready)
 	{
 	{
@@ -827,7 +828,7 @@ void CServerHandler::waitForServer()
 
 
 CConnection * CServerHandler::connectToServer()
 CConnection * CServerHandler::connectToServer()
 {
 {
-#ifndef __ANDROID__
+#ifndef VCMI_ANDROID
 	if(!shared->sr->ready)
 	if(!shared->sr->ready)
 		waitForServer();
 		waitForServer();
 #else
 #else
@@ -850,7 +851,7 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
 	port = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
 	port = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
 	verbose = true;
 	verbose = true;
 
 
-#ifndef __ANDROID__
+#ifndef VCMI_ANDROID
 	boost::interprocess::shared_memory_object::remove("vcmi_memory"); //if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it
 	boost::interprocess::shared_memory_object::remove("vcmi_memory"); //if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it
 	try
 	try
 	{
 	{
@@ -868,8 +869,8 @@ CServerHandler::~CServerHandler()
 void CServerHandler::callServer()
 void CServerHandler::callServer()
 {
 {
 	setThreadName("CServerHandler::callServer");
 	setThreadName("CServerHandler::callServer");
-	std::string logName = VCMIDirs::get().userCachePath() + "/server_log.txt";
-	std::string comm = VCMIDirs::get().serverPath() + " --port=" + port + " > " + logName;
+	const std::string logName = (VCMIDirs::get().userCachePath() / "server_log.txt").string();
+	const std::string comm = VCMIDirs::get().serverPath().string() + " --port=" + port + " > \"" + logName + '\"';
 	int result = std::system(comm.c_str());
 	int result = std::system(comm.c_str());
 	if (result == 0)
 	if (result == 0)
         logNetwork->infoStream() << "Server closed correctly";
         logNetwork->infoStream() << "Server closed correctly";

+ 1 - 1
editor/Editor.cpp

@@ -13,7 +13,7 @@ Editor::Editor(QWidget *parent)
 {
 {
 	// Setup default logging(enough for now)
 	// Setup default logging(enough for now)
 	console = new CConsoleHandler;
 	console = new CConsoleHandler;
-	CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Editor_log.txt", console);
+	CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() / "VCMI_Editor_log.txt", console);
 	logConfig.configureDefault();
 	logConfig.configureDefault();
 
 
 	preinitDLL(console);
 	preinitDLL(console);

+ 10 - 1
launcher/StdInc.h

@@ -8,4 +8,13 @@
 #include <QVector>
 #include <QVector>
 #include <QList>
 #include <QList>
 #include <QString>
 #include <QString>
-#include <QFile>
+#include <QFile>
+
+inline QString pathToQString(const boost::filesystem::path & path)
+{
+#ifdef VCMI_WINDOWS
+	return QString::fromStdWString(path.wstring());
+#else
+	return QString::fromStdString(path.string());
+#endif
+}

+ 2 - 2
launcher/launcherdirs.cpp

@@ -18,10 +18,10 @@ CLauncherDirs & CLauncherDirs::get()
 
 
 QString CLauncherDirs::downloadsPath()
 QString CLauncherDirs::downloadsPath()
 {
 {
-	return QString::fromUtf8(VCMIDirs::get().userCachePath().c_str()) + "/downloads";
+	return pathToQString(VCMIDirs::get().userCachePath() / "downloads");
 }
 }
 
 
 QString CLauncherDirs::modsPath()
 QString CLauncherDirs::modsPath()
 {
 {
-	return QString::fromUtf8(VCMIDirs::get().userDataPath().c_str()) + "/Mods";
+	return pathToQString(VCMIDirs::get().userDataPath() / "Mods");
 }
 }

+ 4 - 4
launcher/mainwindow_moc.cpp

@@ -13,15 +13,15 @@
 void MainWindow::load()
 void MainWindow::load()
 {
 {
 	console = new CConsoleHandler;
 	console = new CConsoleHandler;
-	CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Launcher_log.txt", console);
+	CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() / "VCMI_Launcher_log.txt", console);
 	logConfig.configureDefault();
 	logConfig.configureDefault();
 
 
 	CResourceHandler::initialize();
 	CResourceHandler::initialize();
 	CResourceHandler::load("config/filesystem.json");
 	CResourceHandler::load("config/filesystem.json");
 
 
 	for (auto & string : VCMIDirs::get().dataPaths())
 	for (auto & string : VCMIDirs::get().dataPaths())
-		QDir::addSearchPath("icons", QString::fromUtf8(string.c_str()) + "/launcher/icons");
-	QDir::addSearchPath("icons", QString::fromUtf8(VCMIDirs::get().userDataPath().c_str()) + "/launcher/icons");
+		QDir::addSearchPath("icons", pathToQString(string / "launcher" / "icons"));
+	QDir::addSearchPath("icons", pathToQString(VCMIDirs::get().userDataPath() / "launcher" / "icons"));
 
 
 	settings.init();
 	settings.init();
 }
 }
@@ -46,7 +46,7 @@ MainWindow::~MainWindow()
 
 
 void MainWindow::on_startGameButon_clicked()
 void MainWindow::on_startGameButon_clicked()
 {
 {
-	startExecutable(QString::fromUtf8(VCMIDirs::get().clientPath().c_str()));
+	startExecutable(pathToQString(VCMIDirs::get().clientPath()));
 }
 }
 
 
 void MainWindow::startExecutable(QString name)
 void MainWindow::startExecutable(QString name)

+ 1 - 1
launcher/modManager/cmodmanager.cpp

@@ -39,7 +39,7 @@ CModManager::CModManager(CModList * modList):
 
 
 QString CModManager::settingsPath()
 QString CModManager::settingsPath()
 {
 {
-	return QString::fromUtf8(VCMIDirs::get().userConfigPath().c_str()) + "/modSettings.json";
+	return pathToQString(VCMIDirs::get().userConfigPath() / "modSettings.json");
 }
 }
 
 
 void CModManager::loadModSettings()
 void CModManager::loadModSettings()

+ 3 - 3
launcher/settingsView/csettingsview_moc.cpp

@@ -46,9 +46,9 @@ void CSettingsView::loadSettings()
 	for (auto entry : urls.Vector())
 	for (auto entry : urls.Vector())
 		ui->plainTextEditRepos->appendPlainText(QString::fromUtf8(entry.String().c_str()));
 		ui->plainTextEditRepos->appendPlainText(QString::fromUtf8(entry.String().c_str()));
 
 
-	ui->lineEditUserDataDir->setText(QString::fromUtf8(VCMIDirs::get().userDataPath().c_str()));
-	ui->lineEditGameDir->setText(QString::fromUtf8(M_DATA_DIR));
-	ui->lineEditTempDir->setText(QString::fromUtf8(VCMIDirs::get().userCachePath().c_str()));
+	ui->lineEditUserDataDir->setText(pathToQString(VCMIDirs::get().userDataPath()));
+	ui->lineEditGameDir->setText(pathToQString(VCMIDirs::get().binaryPath()));
+	ui->lineEditTempDir->setText(pathToQString(VCMIDirs::get().userCachePath()));
 
 
 	std::string encoding = settings["general"]["encoding"].String();
 	std::string encoding = settings["general"]["encoding"].String();
 	size_t encodingIndex = boost::range::find(knownEncodingsList, encoding) - knownEncodingsList;
 	size_t encodingIndex = boost::range::find(knownEncodingsList, encoding) - knownEncodingsList;

+ 6 - 17
lib/BattleHex.cpp

@@ -44,18 +44,6 @@ BattleHex& BattleHex::moveInDir(EDir dir, bool hasToBeValid)
 	return *this;
 	return *this;
 }
 }
 
 
-void BattleHex::operator+=(EDir dir)
-{
-	moveInDir(dir);
-}
-
-BattleHex BattleHex::operator+(EDir dir) const
-{
-	BattleHex ret(*this);
-	ret += dir;
-	return ret;
-}
-
 std::vector<BattleHex> BattleHex::neighbouringTiles() const
 std::vector<BattleHex> BattleHex::neighbouringTiles() const
 {
 {
 	std::vector<BattleHex> ret;
 	std::vector<BattleHex> ret;
@@ -93,17 +81,18 @@ char BattleHex::getDistance(BattleHex hex1, BattleHex hex2)
 {	
 {	
 	int y1 = hex1.getY(), 
 	int y1 = hex1.getY(), 
 		y2 = hex2.getY();
 		y2 = hex2.getY();
-
-	int x1 = hex1.getX() + y1 / 2.0, 
-		x2 = hex2.getX() + y2 / 2.0;
+	
+	// FIXME: Omit floating point arithmetics
+	int x1 = (int)(hex1.getX() + y1 * 0.5),
+		x2 = (int)(hex2.getX() + y2 * 0.5);
 
 
 	int xDst = x2 - x1,
 	int xDst = x2 - x1,
 		yDst = y2 - y1;
 		yDst = y2 - y1;
 
 
 	if ((xDst >= 0 && yDst >= 0) || (xDst < 0 && yDst < 0)) 
 	if ((xDst >= 0 && yDst >= 0) || (xDst < 0 && yDst < 0)) 
 		return std::max(std::abs(xDst), std::abs(yDst));
 		return std::max(std::abs(xDst), std::abs(yDst));
-	else 
-		return std::abs(xDst) + std::abs(yDst);
+	
+	return std::abs(xDst) + std::abs(yDst);
 }
 }
 
 
 void BattleHex::checkAndPush(BattleHex tile, std::vector<BattleHex> & ret)
 void BattleHex::checkAndPush(BattleHex tile, std::vector<BattleHex> & ret)

+ 15 - 28
lib/BattleHex.h

@@ -17,22 +17,16 @@
 struct DLL_LINKAGE BattleHex
 struct DLL_LINKAGE BattleHex
 {
 {
 	static const si16 INVALID = -1;
 	static const si16 INVALID = -1;
-	enum EDir{RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, LEFT, TOP_LEFT, TOP_RIGHT};
+	enum EDir { RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, LEFT, TOP_LEFT, TOP_RIGHT };
 
 
 	si16 hex;
 	si16 hex;
 
 
 	BattleHex() : hex(INVALID) {}
 	BattleHex() : hex(INVALID) {}
 	BattleHex(si16 _hex) : hex(_hex) {}
 	BattleHex(si16 _hex) : hex(_hex) {}
 	
 	
-	operator si16() const
-	{
-		return hex;
-	}
+	operator si16() const { return hex; }
 
 
-	bool isValid() const
-	{
-		return hex >= 0 && hex < GameConstants::BFIELD_SIZE;
-	}
+	bool isValid() const { return hex >= 0 && hex < GameConstants::BFIELD_SIZE; }
 
 
 	template<typename inttype>
 	template<typename inttype>
 	BattleHex(inttype x, inttype y)
 	BattleHex(inttype x, inttype y)
@@ -61,9 +55,7 @@ struct DLL_LINKAGE BattleHex
 	void setXY(si16 x, si16 y, bool hasToBeValid = true)
 	void setXY(si16 x, si16 y, bool hasToBeValid = true)
 	{
 	{
 		if(hasToBeValid)
 		if(hasToBeValid)
-		{
-			assert(x >= 0 && x < GameConstants::BFIELD_WIDTH && y >= 0  && y < GameConstants::BFIELD_HEIGHT);
-		}
+			assert(x >= 0 && x < GameConstants::BFIELD_WIDTH && y >= 0 && y < GameConstants::BFIELD_HEIGHT);
 		hex = x + y * GameConstants::BFIELD_WIDTH;
 		hex = x + y * GameConstants::BFIELD_WIDTH;
 	}
 	}
 
 
@@ -73,28 +65,23 @@ struct DLL_LINKAGE BattleHex
 		setXY(xy.first, xy.second);
 		setXY(xy.first, xy.second);
 	}
 	}
 
 
-	si16 getY() const
-	{
-		return hex / GameConstants::BFIELD_WIDTH;
-	}
+	si16 getY() const { return hex / GameConstants::BFIELD_WIDTH; }
+	si16 getX() const { return hex % GameConstants::BFIELD_WIDTH; }
 
 
-	si16 getX() const
-	{
-		int pos = hex - getY() * GameConstants::BFIELD_WIDTH;
-		return pos;
-	}
-
-	std::pair<si16, si16> getXY() const
-	{
-		return std::make_pair(getX(), getY());
-	}
+	std::pair<si16, si16> getXY() const { return std::make_pair(getX(), getY()); }
 
 
 	//moving to direction
 	//moving to direction
 	BattleHex& moveInDir(EDir dir, bool hasToBeValid = true); 
 	BattleHex& moveInDir(EDir dir, bool hasToBeValid = true); 
-	void operator+=(EDir dir); //sugar for above
+	BattleHex& operator+=(EDir dir) { return moveInDir(dir); } //sugar for above
 
 
 	//generates new BattleHex moved by given dir
 	//generates new BattleHex moved by given dir
-	BattleHex operator+(EDir dir) const;
+	BattleHex movedInDir(EDir dir, bool hasToBeValid = true) const
+	{
+		BattleHex result(*this);
+		result.moveInDir(dir, hasToBeValid);
+		return result;
+	}
+	BattleHex operator+(EDir dir) const { return movedInDir(dir); }
 
 
 	std::vector<BattleHex> neighbouringTiles() const;
 	std::vector<BattleHex> neighbouringTiles() const;
 
 

+ 17 - 7
lib/CConsoleHandler.cpp

@@ -17,7 +17,7 @@ boost::mutex CConsoleHandler::smx;
 
 
 DLL_LINKAGE CConsoleHandler * console = nullptr;
 DLL_LINKAGE CConsoleHandler * console = nullptr;
 
 
-#ifndef _WIN32
+#ifndef VCMI_WINDOWS
 	typedef std::string TColor;
 	typedef std::string TColor;
 	#define CONSOLE_GREEN "\x1b[1;32m"
 	#define CONSOLE_GREEN "\x1b[1;32m"
 	#define CONSOLE_RED "\x1b[1;31m"
 	#define CONSOLE_RED "\x1b[1;31m"
@@ -27,7 +27,6 @@ DLL_LINKAGE CConsoleHandler * console = nullptr;
 	#define CONSOLE_GRAY "\x1b[1;30m"
 	#define CONSOLE_GRAY "\x1b[1;30m"
 	#define CONSOLE_TEAL "\x1b[1;36m"
 	#define CONSOLE_TEAL "\x1b[1;36m"
 #else
 #else
-	#define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
 	#include <Windows.h>
 	#include <Windows.h>
 #ifndef __MINGW32__
 #ifndef __MINGW32__
 	#include <dbghelp.h>
 	#include <dbghelp.h>
@@ -36,6 +35,7 @@ DLL_LINKAGE CConsoleHandler * console = nullptr;
 	typedef WORD TColor;
 	typedef WORD TColor;
 	HANDLE handleIn;
 	HANDLE handleIn;
 	HANDLE handleOut;
 	HANDLE handleOut;
+	HANDLE handleErr;
 	#define CONSOLE_GREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY
 	#define CONSOLE_GREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY
 	#define CONSOLE_RED FOREGROUND_RED | FOREGROUND_INTENSITY
 	#define CONSOLE_RED FOREGROUND_RED | FOREGROUND_INTENSITY
 	#define CONSOLE_MAGENTA FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY
 	#define CONSOLE_MAGENTA FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY
@@ -43,11 +43,13 @@ DLL_LINKAGE CConsoleHandler * console = nullptr;
 	#define CONSOLE_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
 	#define CONSOLE_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
 	#define CONSOLE_GRAY FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
 	#define CONSOLE_GRAY FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
 	#define CONSOLE_TEAL FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
 	#define CONSOLE_TEAL FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
+
+	static TColor defErrColor;
 #endif
 #endif
 
 
 static TColor defColor;
 static TColor defColor;
 
 
-#ifdef _WIN32
+#ifdef VCMI_WINDOWS
 
 
 void printWinError()
 void printWinError()
 {
 {
@@ -178,8 +180,11 @@ void CConsoleHandler::setColor(EConsoleTextColor::EConsoleTextColor color)
         colorCode = defColor;
         colorCode = defColor;
 		break;
 		break;
 	}
 	}
-#ifdef _WIN32
+#ifdef VCMI_WINDOWS
     SetConsoleTextAttribute(handleOut, colorCode);
     SetConsoleTextAttribute(handleOut, colorCode);
+	if (color == EConsoleTextColor::DEFAULT)
+		colorCode = defErrColor;
+	SetConsoleTextAttribute(handleErr, colorCode);
 #else
 #else
     std::cout << colorCode;
     std::cout << colorCode;
 #endif
 #endif
@@ -194,7 +199,7 @@ int CConsoleHandler::run()
 
 
 	while ( std::cin.good() )
 	while ( std::cin.good() )
 	{
 	{
-#ifndef _WIN32
+#ifndef VCMI_WINDOWS
 		//check if we have some unreaded symbols
 		//check if we have some unreaded symbols
 		if (std::cin.rdbuf()->in_avail())
 		if (std::cin.rdbuf()->in_avail())
 		{
 		{
@@ -216,12 +221,17 @@ int CConsoleHandler::run()
 }
 }
 CConsoleHandler::CConsoleHandler() : thread(nullptr)
 CConsoleHandler::CConsoleHandler() : thread(nullptr)
 {
 {
-#ifdef _WIN32
+#ifdef VCMI_WINDOWS
 	handleIn = GetStdHandle(STD_INPUT_HANDLE);
 	handleIn = GetStdHandle(STD_INPUT_HANDLE);
 	handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
 	handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
+	handleErr = GetStdHandle(STD_ERROR_HANDLE);
+
 	CONSOLE_SCREEN_BUFFER_INFO csbi;
 	CONSOLE_SCREEN_BUFFER_INFO csbi;
 	GetConsoleScreenBufferInfo(handleOut,&csbi);
 	GetConsoleScreenBufferInfo(handleOut,&csbi);
 	defColor = csbi.wAttributes;
 	defColor = csbi.wAttributes;
+
+	GetConsoleScreenBufferInfo(handleErr, &csbi);
+	defErrColor = csbi.wAttributes;
 #ifndef _DEBUG
 #ifndef _DEBUG
 	SetUnhandledExceptionFilter(onUnhandledException);
 	SetUnhandledExceptionFilter(onUnhandledException);
 #endif
 #endif
@@ -241,7 +251,7 @@ void CConsoleHandler::end()
 {
 {
 	if (thread)
 	if (thread)
 	{
 	{
-#ifndef _WIN32
+#ifndef VCMI_WINDOWS
 		thread->interrupt();
 		thread->interrupt();
 #else
 #else
 		TerminateThread(thread->native_handle(),0);
 		TerminateThread(thread->native_handle(),0);

+ 2 - 2
lib/CConsoleHandler.h

@@ -38,7 +38,7 @@ public:
     template<typename T> void print(const T &data, bool addNewLine = false, EConsoleTextColor::EConsoleTextColor color = EConsoleTextColor::DEFAULT, bool printToStdErr = false)
     template<typename T> void print(const T &data, bool addNewLine = false, EConsoleTextColor::EConsoleTextColor color = EConsoleTextColor::DEFAULT, bool printToStdErr = false)
 	{
 	{
         TLockGuard _(smx);
         TLockGuard _(smx);
-#ifndef _WIN32
+#ifndef VCMI_WINDOWS
 		// with love from ffmpeg - library is trying to print some warnings from separate thread
 		// with love from ffmpeg - library is trying to print some warnings from separate thread
 		// this results in broken console on Linux. Lock stdout to print all our data at once
 		// this results in broken console on Linux. Lock stdout to print all our data at once
 		flockfile(stdout);
 		flockfile(stdout);
@@ -70,7 +70,7 @@ public:
         }
         }
 
 
         if(color != EConsoleTextColor::DEFAULT) setColor(EConsoleTextColor::DEFAULT);
         if(color != EConsoleTextColor::DEFAULT) setColor(EConsoleTextColor::DEFAULT);
-#ifndef _WIN32
+#ifndef VCMI_WINDOWS
 		funlockfile(stdout);
 		funlockfile(stdout);
 #endif
 #endif
 	}
 	}

+ 35 - 32
lib/CGameInterface.cpp

@@ -4,8 +4,7 @@
 #include "BattleState.h"
 #include "BattleState.h"
 #include "VCMIDirs.h"
 #include "VCMIDirs.h"
 
 
-#ifdef _WIN32
-	#define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
+#ifdef VCMI_WINDOWS
 	#include <windows.h> //for .dll libs
 	#include <windows.h> //for .dll libs
 #else
 #else
 	#include <dlfcn.h>
 	#include <dlfcn.h>
@@ -22,7 +21,7 @@
  *
  *
  */
  */
 
 
-#ifdef __ANDROID__
+#ifdef VCMI_ANDROID
 // we can't use shared libraries on Android so here's a hack
 // we can't use shared libraries on Android so here's a hack
 extern "C" DLL_EXPORT void VCAI_GetAiName(char* name);
 extern "C" DLL_EXPORT void VCAI_GetAiName(char* name);
 extern "C" DLL_EXPORT void VCAI_GetNewAI(shared_ptr<CGlobalAI> &out);
 extern "C" DLL_EXPORT void VCAI_GetNewAI(shared_ptr<CGlobalAI> &out);
@@ -35,7 +34,7 @@ extern "C" DLL_EXPORT void BattleAI_GetNewBattleAI(shared_ptr<CBattleGameInterfa
 #endif
 #endif
 
 
 template<typename rett>
 template<typename rett>
-shared_ptr<rett> createAny(std::string dllname, std::string methodName)
+shared_ptr<rett> createAny(const boost::filesystem::path& libpath, const std::string& methodName)
 {
 {
 	typedef void(*TGetAIFun)(shared_ptr<rett>&); 
 	typedef void(*TGetAIFun)(shared_ptr<rett>&); 
 	typedef void(*TGetNameFun)(char*); 
 	typedef void(*TGetNameFun)(char*); 
@@ -45,56 +44,60 @@ shared_ptr<rett> createAny(std::string dllname, std::string methodName)
 	TGetAIFun getAI = nullptr;
 	TGetAIFun getAI = nullptr;
 	TGetNameFun getName = nullptr;
 	TGetNameFun getName = nullptr;
 
 
-#ifdef __ANDROID__
+#ifdef VCMI_ANDROID
 	// this is awful but it seems using shared libraries on some devices is even worse
 	// this is awful but it seems using shared libraries on some devices is even worse
-	if (dllname.find("libVCAI.so") != std::string::npos) {
+	const std::string filename = libpath.filename().string();
+	if (filename == "libVCAI.so")
+	{
 		getName = (TGetNameFun)VCAI_GetAiName;
 		getName = (TGetNameFun)VCAI_GetAiName;
 		getAI = (TGetAIFun)VCAI_GetNewAI;
 		getAI = (TGetAIFun)VCAI_GetNewAI;
-	} else if (dllname.find("libStupidAI.so") != std::string::npos) {
+	}
+	else if (filename == "libStupidAI.so")
+	{
 		getName = (TGetNameFun)StupidAI_GetAiName;
 		getName = (TGetNameFun)StupidAI_GetAiName;
 		getAI = (TGetAIFun)StupidAI_GetNewBattleAI;
 		getAI = (TGetAIFun)StupidAI_GetNewBattleAI;
-	} else if (dllname.find("libBattleAI.so") != std::string::npos) {
+	}
+	else if (filename == "libBattleAI.so")
+	{
 		getName = (TGetNameFun)BattleAI_GetAiName;
 		getName = (TGetNameFun)BattleAI_GetAiName;
 		getAI = (TGetAIFun)BattleAI_GetNewBattleAI;
 		getAI = (TGetAIFun)BattleAI_GetNewBattleAI;
-	} else {
-		throw std::runtime_error("Don't know what to do with " + dllname + " and method " + methodName);
 	}
 	}
-#else
-
-#ifdef _WIN32
-	HINSTANCE dll = LoadLibraryA(dllname.c_str());
+	else
+		throw std::runtime_error("Don't know what to do with " + libpath.string() + " and method " + methodName);
+#else // !VCMI_ANDROID
+#ifdef VCMI_WINDOWS
+	HMODULE dll = LoadLibraryW(libpath.c_str());
 	if (dll)
 	if (dll)
 	{
 	{
-		getName = (TGetNameFun)GetProcAddress(dll,"GetAiName");
-		getAI = (TGetAIFun)GetProcAddress(dll,methodName.c_str());
+		getName = (TGetNameFun)GetProcAddress(dll, "GetAiName");
+		getAI = (TGetAIFun)GetProcAddress(dll, methodName.c_str());
 	}
 	}
-#else
-	void *dll = dlopen(dllname.c_str(), RTLD_LOCAL | RTLD_LAZY);
+#else // !VCMI_WINDOWS
+	void *dll = dlopen(libpath.string().c_str(), RTLD_LOCAL | RTLD_LAZY);
 	if (dll)
 	if (dll)
 	{
 	{
-		getName = (TGetNameFun)dlsym(dll,"GetAiName");
-		getAI = (TGetAIFun)dlsym(dll,methodName.c_str());
+		getName = (TGetNameFun)dlsym(dll, "GetAiName");
+		getAI = (TGetAIFun)dlsym(dll, methodName.c_str());
 	}
 	}
 	else
 	else
         logGlobal->errorStream() << "Error: " << dlerror();
         logGlobal->errorStream() << "Error: " << dlerror();
-#endif
+#endif // VCMI_WINDOWS
 	if (!dll)
 	if (!dll)
 	{
 	{
-        logGlobal->errorStream() << "Cannot open dynamic library ("<<dllname<<"). Throwing...";
+		logGlobal->errorStream() << "Cannot open dynamic library ("<<libpath<<"). Throwing...";
 		throw std::runtime_error("Cannot open dynamic library");
 		throw std::runtime_error("Cannot open dynamic library");
 	}
 	}
 	else if(!getName || !getAI)
 	else if(!getName || !getAI)
 	{
 	{
-        logGlobal->errorStream() << dllname << " does not export method " << methodName;
-#ifdef _WIN32
+		logGlobal->errorStream() << libpath << " does not export method " << methodName;
+#ifdef VCMI_WINDOWS
 		FreeLibrary(dll);
 		FreeLibrary(dll);
 #else
 #else
 		dlclose(dll);
 		dlclose(dll);
 #endif
 #endif
 		throw std::runtime_error("Cannot find method " + methodName);
 		throw std::runtime_error("Cannot find method " + methodName);
 	}
 	}
-
-#endif // __ANDROID__
+#endif // VCMI_ANDROID
 
 
 	getName(temp);
 	getName(temp);
     logGlobal->infoStream() << "Loaded " << temp;
     logGlobal->infoStream() << "Loaded " << temp;
@@ -108,13 +111,13 @@ shared_ptr<rett> createAny(std::string dllname, std::string methodName)
 }
 }
 
 
 template<typename rett>
 template<typename rett>
-shared_ptr<rett> createAnyAI(std::string dllname, std::string methodName)
+shared_ptr<rett> createAnyAI(std::string dllname, const std::string& methodName)
 {
 {
-    logGlobal->infoStream() << "Opening " << dllname;
-	std::string filename = VCMIDirs::get().libraryName(dllname);
-
-	auto ret = createAny<rett>(VCMIDirs::get().libraryPath() + "/AI/" + filename, methodName);
-	ret->dllName = dllname;
+	logGlobal->infoStream() << "Opening " << dllname;
+	const boost::filesystem::path filePath =
+		VCMIDirs::get().libraryPath() / "AI" / VCMIDirs::get().libraryName(dllname);
+	auto ret = createAny<rett>(filePath, methodName);
+	ret->dllName = std::move(dllname);
 	return ret;
 	return ret;
 }
 }
 
 

+ 3 - 3
lib/CThreadHelper.cpp

@@ -1,9 +1,9 @@
 #include "StdInc.h"
 #include "StdInc.h"
 #include "CThreadHelper.h"
 #include "CThreadHelper.h"
 
 
-#ifdef _WIN32
+#ifdef VCMI_WINDOWS
 	#include <windows.h>
 	#include <windows.h>
-#elif !defined(__APPLE__)
+#elif !defined(VCMI_APPLE)
 	#include <sys/prctl.h>
 	#include <sys/prctl.h>
 #endif
 #endif
 /*
 /*
@@ -49,7 +49,7 @@ void CThreadHelper::processTasks()
 // NOTE: on *nix string will be trimmed to 16 symbols
 // NOTE: on *nix string will be trimmed to 16 symbols
 void setThreadName(const std::string &name)
 void setThreadName(const std::string &name)
 {
 {
-#ifdef _WIN32
+#ifdef VCMI_WINDOWS
 #ifndef __GNUC__
 #ifndef __GNUC__
 	//follows http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
 	//follows http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
 	const DWORD MS_VC_EXCEPTION=0x406D1388;
 	const DWORD MS_VC_EXCEPTION=0x406D1388;

+ 15 - 17
lib/CondSh.h

@@ -17,50 +17,48 @@ template <typename T> struct CondSh
 	boost::condition_variable cond;
 	boost::condition_variable cond;
 	boost::mutex mx;
 	boost::mutex mx;
 
 
-	CondSh()
-	{}
-
-	CondSh(T t)
-	{
-		data = t;
-	}
+	CondSh() {}
+	CondSh(T t) : data(t) {}
 
 
+	// set data
 	void set(T t)
 	void set(T t)
 	{
 	{
 		boost::unique_lock<boost::mutex> lock(mx); 
 		boost::unique_lock<boost::mutex> lock(mx); 
-		data=t;
+		data = t;
 	} 
 	} 
 
 
-	void setn(T t) //set data and notify
+	// set data and notify
+	void setn(T t)
 	{
 	{
-		{
-			boost::unique_lock<boost::mutex> lock(mx); 
-			data=t;
-		}
+		set(t);
 		cond.notify_all();
 		cond.notify_all();
 	};
 	};
 
 
-	T get() //get stored value
+	// get stored value
+	T get()
 	{
 	{
 		boost::unique_lock<boost::mutex> lock(mx); 
 		boost::unique_lock<boost::mutex> lock(mx); 
 		return data;
 		return data;
 	}
 	}
 
 
-	void waitWhileTrue() //waits until data is set to false
+	// waits until data is set to false
+	void waitWhileTrue()
 	{
 	{
 		boost::unique_lock<boost::mutex> un(mx);
 		boost::unique_lock<boost::mutex> un(mx);
 		while(data)
 		while(data)
 			cond.wait(un);
 			cond.wait(un);
 	}
 	}
 
 
-	void waitWhile(const T &t) //waits while data is set to arg
+	// waits while data is set to arg
+	void waitWhile(const T & t)
 	{
 	{
 		boost::unique_lock<boost::mutex> un(mx);
 		boost::unique_lock<boost::mutex> un(mx);
 		while(data == t)
 		while(data == t)
 			cond.wait(un);
 			cond.wait(un);
 	}
 	}
 
 
-	void waitUntil(const T &t) //waits until data is set to arg
+	// waits until data is set to arg
+	void waitUntil(const T & t)
 	{
 	{
 		boost::unique_lock<boost::mutex> un(mx);
 		boost::unique_lock<boost::mutex> un(mx);
 		while(data != t)
 		while(data != t)

+ 9 - 9
lib/Connection.cpp

@@ -347,7 +347,7 @@ void CSaveFile::putMagicBytes( const std::string &text )
 	write(text.c_str(), text.length());
 	write(text.c_str(), text.length());
 }
 }
 
 
-CLoadFile::CLoadFile(const std::string &fname, int minimalVersion /*= version*/)
+CLoadFile::CLoadFile(const boost::filesystem::path & fname, int minimalVersion /*= version*/)
 {
 {
 	registerTypes(*this);
 	registerTypes(*this);
 	openNextFile(fname, minimalVersion);
 	openNextFile(fname, minimalVersion);
@@ -363,33 +363,33 @@ int CLoadFile::read(void * data, unsigned size)
 	return size;
 	return size;
 }
 }
 
 
-void CLoadFile::openNextFile(const std::string &fname, int minimalVersion)
+void CLoadFile::openNextFile(const boost::filesystem::path & fname, int minimalVersion)
 {
 {
 	assert(!reverseEndianess);
 	assert(!reverseEndianess);
 	assert(minimalVersion <= version);
 	assert(minimalVersion <= version);
 
 
 	try
 	try
 	{
 	{
-		fName = fname;
-		sfile = make_unique<std::ifstream>(fname, std::ios::binary);
+		fName = fname.string();
+		sfile = make_unique<boost::filesystem::ifstream>(fname, std::ios::binary);
 		sfile->exceptions(std::ifstream::failbit | std::ifstream::badbit); //we throw a lot anyway
 		sfile->exceptions(std::ifstream::failbit | std::ifstream::badbit); //we throw a lot anyway
 
 
 		if(!(*sfile))
 		if(!(*sfile))
-			THROW_FORMAT("Error: cannot open to read %s!", fname);
+			THROW_FORMAT("Error: cannot open to read %s!", fName);
 
 
 		//we can read
 		//we can read
 		char buffer[4];
 		char buffer[4];
 		sfile->read(buffer, 4);
 		sfile->read(buffer, 4);
 		if(std::memcmp(buffer,"VCMI",4))
 		if(std::memcmp(buffer,"VCMI",4))
-			THROW_FORMAT("Error: not a VCMI file(%s)!", fname);
+			THROW_FORMAT("Error: not a VCMI file(%s)!", fName);
 
 
 		*this >> fileVersion;	
 		*this >> fileVersion;	
 		if(fileVersion < minimalVersion)
 		if(fileVersion < minimalVersion)
-			THROW_FORMAT("Error: too old file format (%s)!", fname);
+			THROW_FORMAT("Error: too old file format (%s)!", fName);
 
 
 		if(fileVersion > version)
 		if(fileVersion > version)
 		{
 		{
-			logGlobal->warnStream() << boost::format("Warning format version mismatch: found %d when current is %d! (file %s)\n") % fileVersion % version % fname;
+			logGlobal->warnStream() << boost::format("Warning format version mismatch: found %d when current is %d! (file %s)\n") % fileVersion % version % fName;
 
 
 			auto versionptr = (char*)&fileVersion;
 			auto versionptr = (char*)&fileVersion;
 			std::reverse(versionptr, versionptr + 4);
 			std::reverse(versionptr, versionptr + 4);
@@ -401,7 +401,7 @@ void CLoadFile::openNextFile(const std::string &fname, int minimalVersion)
 				reverseEndianess = true;
 				reverseEndianess = true;
 			}
 			}
 			else
 			else
-				THROW_FORMAT("Error: too new file format (%s)!", fname);
+				THROW_FORMAT("Error: too new file format (%s)!", fName);
 		}
 		}
 	}
 	}
 	catch(...)
 	catch(...)

+ 4 - 4
lib/Connection.h

@@ -1530,17 +1530,17 @@ class DLL_LINKAGE CLoadFile
 
 
 public:
 public:
 	std::string fName;
 	std::string fName;
-	unique_ptr<std::ifstream> sfile;
+	unique_ptr<boost::filesystem::ifstream> sfile;
 
 
-	CLoadFile(const std::string &fname, int minimalVersion = version); //throws!
+	CLoadFile(const boost::filesystem::path & fname, int minimalVersion = version); //throws!
 	~CLoadFile();
 	~CLoadFile();
 	int read(void * data, unsigned size); //throws!
 	int read(void * data, unsigned size); //throws!
 
 
-	void openNextFile(const std::string &fname, int minimalVersion); //throws!
+	void openNextFile(const boost::filesystem::path & fname, int minimalVersion); //throws!
 	void clear();
 	void clear();
     void reportState(CLogger * out);
     void reportState(CLogger * out);
 
 
-	void checkMagicBytes(const std::string &text);
+	void checkMagicBytes(const std::string & text);
 };
 };
 
 
 class DLL_LINKAGE CLoadIntegrityValidator : public CISer<CLoadIntegrityValidator>
 class DLL_LINKAGE CLoadIntegrityValidator : public CISer<CLoadIntegrityValidator>

+ 478 - 153
lib/VCMIDirs.cpp

@@ -1,6 +1,3 @@
-#include "StdInc.h"
-#include "VCMIDirs.h"
-
 /*
 /*
  * VCMIDirs.cpp, part of VCMI engine
  * VCMIDirs.cpp, part of VCMI engine
  *
  *
@@ -11,216 +8,504 @@
  *
  *
  */
  */
 
 
-static VCMIDirs VCMIDirsGlobal;
-
-VCMIDirs::VCMIDirs()
-{
-	// initialize local directory and create folders to which VCMI needs write access
-	boost::filesystem::create_directory(userDataPath());
-	boost::filesystem::create_directory(userCachePath());
-	boost::filesystem::create_directory(userConfigPath());
-	boost::filesystem::create_directory(userSavePath());
-}
+#include "StdInc.h"
+#include "VCMIDirs.h"
 
 
-VCMIDirs & VCMIDirs::get()
-{
-	return VCMIDirsGlobal;
-}
+namespace bfs = boost::filesystem;
 
 
-//FIXME: find way to at least decrease size of this ifdef (along with cleanup in CMake)
-#if defined(_WIN32)
+bfs::path IVCMIDirs::userSavePath() const { return userDataPath() / "Saves"; }
 
 
-std::string VCMIDirs::userCachePath() const
+void IVCMIDirs::init()
 {
 {
-	return userDataPath();
+	// TODO: Log errors
+	bfs::create_directory(userDataPath());
+	bfs::create_directory(userCachePath());
+	bfs::create_directory(userConfigPath());
+	bfs::create_directory(userSavePath());
 }
 }
 
 
-std::string VCMIDirs::userConfigPath() const
+#ifdef VCMI_WINDOWS
+
+#include <Windows.h>
+#include <Shlobj.h>
+#include <Shellapi.h>
+
+// Generates script file named _temp.bat in 'to' directory and runs it
+// Script will:
+// - Wait util 'exeName' ends.
+// - Copy all files from 'from' to 'to'
+// - Ask user to replace files existed in 'to'.
+// - Run 'exeName'
+// - Delete itself.
+bool StartBatchCopyDataProgram(
+	const bfs::path& from, const bfs::path& to, const bfs::path& exeName,
+	const bfs::path& currentPath = bfs::current_path())
 {
 {
-	return userDataPath() + "/config";
+	static const char base[] =
+		"@echo off"												"\n"
+		"echo Preparing to move VCMI data system."				"\n"
+
+		":CLIENT_RUNNING_LOOP"									"\n"
+		"TASKLIST | FIND /I %1% > nul"							"\n"
+		"IF ERRORLEVEL 1 ("										"\n"
+			"GOTO CLIENT_NOT_RUNNING"							"\n"
+		") ELSE ("												"\n"
+			"echo %1% is still running..."						"\n"
+			"echo Waiting until process ends..."				"\n"
+			"ping 1.1.1.1 -n 1 -w 3000 > nul"					"\n" // Sleep ~3 seconds. I love Windows :)
+			"goto :CLIENT_RUNNING_LOOP"							"\n"
+		")"														"\n"
+
+		":CLIENT_NOT_RUNNING"									"\n"
+		"echo %1% turned off..."								"\n"
+		"echo Attempt to move datas."							"\n"
+		"echo From: %2%"										"\n"
+		"echo To: %4%"											"\n"
+		"echo Please resolve any conflicts..."					"\n"
+		"move /-Y %3% %4%"										"\n" // Move all files from %3% to %4%.
+																	 // /-Y ask what to do when file exists in %4%
+		":REMOVE_OLD_DIR"										"\n"
+		"rd %2% || rem"											"\n" // Remove empty directory. Sets error flag if fail.
+		"IF ERRORLEVEL 145 ("									"\n" // Directory not empty
+			"echo Directory %2% is not empty."					"\n"
+			"echo Please move rest of files manually now."		"\n"
+			"pause"												"\n" // Press any key to continue...
+			"goto REMOVE_OLD_DIR"								"\n"
+		")"														"\n"
+		"echo Game data updated succefully."					"\n"
+		"echo Please update your shortcuts."					"\n"
+		"echo Press any key to start a game . . ."				"\n"
+		"pause > nul"											"\n"
+		"%5%"													"\n"
+		"del \"%%~f0\"&exit"									"\n" // Script deletes itself
+		;
+	
+	const auto startGameString =
+		bfs::equivalent(currentPath, from) ?
+		(boost::format("start \"\" %1%") % (to / exeName)) :						// Start game in new path.
+		(boost::format("start \"\" /D %1% %2%") % currentPath % (to / exeName));	// Start game in 'currentPath"
+
+	const bfs::path bathFilename = to / "_temp.bat";
+	bfs::ofstream bathFile(bathFilename, bfs::ofstream::trunc | bfs::ofstream::out);
+	if (!bathFile.is_open())
+		return false;
+	bathFile << (boost::format(base) % exeName % from % (from / "*.*") % to % startGameString.str()).str();
+	bathFile.close();
+
+	std::system(("start \"Updating VCMI datas\" /D \"" + to.string() + "\" \"" + bathFilename.string() + '\"').c_str());
+	// start won't block std::system
+	// /D start bat in other directory insteand of current directory.
+
+	return true;
 }
 }
 
 
-std::string VCMIDirs::userSavePath() const
+class VCMIDirsWIN32 : public IVCMIDirs
 {
 {
-	return userDataPath() + "/Games";
-}
+	public:
+		boost::filesystem::path userDataPath() const override;
+		boost::filesystem::path userCachePath() const override;
+		boost::filesystem::path userConfigPath() const override;
+
+		std::vector<boost::filesystem::path> dataPaths() const override;
+
+		boost::filesystem::path clientPath() const override;
+		boost::filesystem::path serverPath() const override;
 
 
-std::string VCMIDirs::userDataPath() const
+		boost::filesystem::path libraryPath() const override;
+		boost::filesystem::path binaryPath() const override;
+
+		std::string libraryName(const std::string& basename) const override;
+
+		std::string genHelpString() const override;
+
+		void init() override;
+	protected:
+		boost::filesystem::path oldUserDataPath() const;
+		boost::filesystem::path oldUserSavePath() const;
+};
+
+void VCMIDirsWIN32::init()
 {
 {
-	const std::string homeDir = std::getenv("userprofile");
-	return homeDir + "\\vcmi";
-	//return dataPaths()[0];
+	// Call base (init dirs)
+	IVCMIDirs::init();
+
+	// Moves one directory (from) contents to another directory (to)
+	// Shows user the "moving file dialog" and ask to resolve conflits.
+	// If necessary updates current directory.
+	auto moveDirIfExists = [](const bfs::path& from, const bfs::path& to) -> bool
+	{
+		if (!bfs::is_directory(from))
+			return true; // Nothing to do here. Flies away.
+
+		if (bfs::is_empty(from))
+		{
+			if (bfs::current_path() == from)
+				bfs::current_path(to);
+
+			bfs::remove(from);
+			return true; // Nothing to do here. Flies away.
+		}
+
+		if (!bfs::is_directory(to))
+		{
+			// IVCMIDirs::init() should create all destination directories.
+			// TODO: Log fact, that we shouldn't be here.
+			bfs::create_directory(to);
+		}
+
+		// Why the hell path strings should be end with double null :/
+		auto makeDoubleNulled = [](const bfs::path& path) -> std::unique_ptr<wchar_t[]>
+		{
+			const std::wstring& pathStr = path.native();
+			std::unique_ptr<wchar_t[]> result(new wchar_t[pathStr.length() + 2]);
+			
+			size_t i = 0;
+			for (const wchar_t ch : pathStr)
+				result[i++] = ch;
+			result[i++] = L'\0';
+			result[i++] = L'\0';
+
+			return result;
+		};
+
+		auto fromDNulled = makeDoubleNulled(from / L"*.*");
+		auto toDNulled = makeDoubleNulled(to);
+
+		SHFILEOPSTRUCTW fileOp;
+		fileOp.hwnd = GetConsoleWindow();
+		fileOp.wFunc = FO_MOVE;
+		fileOp.pFrom = fromDNulled.get();
+		fileOp.pTo = toDNulled.get();
+		fileOp.fFlags = 0;
+		fileOp.hNameMappings = nullptr;
+		fileOp.lpszProgressTitle = nullptr;
+
+		const int errorCode = SHFileOperationW(&fileOp);
+		if (errorCode != 0) // TODO: Log error. User should try to move files.
+			return false;
+		else if (fileOp.fAnyOperationsAborted) // TODO: Log warn. User aborted operation. User should move files.
+			return false;
+		else if (!bfs::is_empty(from)) // TODO: Log warn. Some files not moved. User should try to move files.
+			return false;
+		
+		if (bfs::current_path() == from)
+			bfs::current_path(to);
+
+		// TODO: Log fact that we moved files succefully.
+		bfs::remove(from);
+		return true;
+	};
+	
+	// Retrieves the fully qualified path for the file that contains the specified module.
+	// The module must have been loaded by the current process.
+	// If this parameter is nullptr, retrieves the path of the executable file of the current process.
+	auto getModulePath = [](HMODULE hModule) -> bfs::path
+	{
+		wchar_t exePathW[MAX_PATH];
+		DWORD nSize = GetModuleFileNameW(hModule, exePathW, MAX_PATH);
+		DWORD error = GetLastError();
+		// WARN: Windows XP don't set ERROR_INSUFFICIENT_BUFFER error.
+		if (nSize != 0 && error != ERROR_INSUFFICIENT_BUFFER)
+			return bfs::path(std::wstring(exePathW, nSize));
+		// TODO: Error handling
+		return bfs::path();
+	};
+
+	// Moves one directory contents to another directory
+	// Shows user the "moving file dialog" and ask to resolve conflicts.
+	// It takes into account that 'from' path can contain current executable.
+	// If necessary closes program and starts update script.
+	auto advancedMoveDirIfExists = [getModulePath, moveDirIfExists](const bfs::path& from, const bfs::path& to) -> bool
+	{
+		const bfs::path executablePath = getModulePath(nullptr);
+
+		// VCMI cann't determine executable path.
+		// Use standard way to move directory and exit function.
+		if (executablePath.empty())
+			return moveDirIfExists(from, to);
+
+		const bfs::path executableName = executablePath.filename();
+
+		// Current executabl isn't in 'from' path.
+		// Use standard way to move directory and exit function.
+		if (!bfs::equivalent(executablePath, from / executableName))
+			return moveDirIfExists(from, to);
+
+		// Try standard way to move directory.
+		// I don't know how other systems, but Windows 8.1 allow to move running executable.
+		if (moveDirIfExists(from, to))
+			return true;
+
+		// Start copying script and exit program.
+		if (StartBatchCopyDataProgram(from, to, executableName))
+			exit(ERROR_SUCCESS);
+		
+		// Everything failed :C
+		return false;
+	};
+
+	moveDirIfExists(oldUserSavePath(), userSavePath());
+	advancedMoveDirIfExists(oldUserDataPath(), userDataPath());
 }
 }
 
 
-std::string VCMIDirs::libraryPath() const
+bfs::path VCMIDirsWIN32::userDataPath() const
 {
 {
+	wchar_t profileDir[MAX_PATH];
+
+	if (SHGetSpecialFolderPathW(nullptr, profileDir, CSIDL_MYDOCUMENTS, FALSE) != FALSE)
+		return bfs::path(profileDir) / "My Games\\vcmi";
+	
 	return ".";
 	return ".";
 }
 }
 
 
-std::string VCMIDirs::clientPath() const
+bfs::path VCMIDirsWIN32::oldUserDataPath() const
 {
 {
-	return libraryPath() + "\\" + "VCMI_client.exe";
-}
+	wchar_t profileDir[MAX_PATH];
+	
+	if (SHGetSpecialFolderPathW(nullptr, profileDir, CSIDL_PROFILE, FALSE) == FALSE) // WinAPI way failed
+	{
+#if defined(_MSC_VER) && _MSC_VER >= 1700
+		wchar_t* buffer;
+		size_t bufferSize;
+		errno_t result = _wdupenv_s(&buffer, &bufferSize, L"userprofile");
+		if (result == 0)
+		{
+			bfs::path result(std::wstring(buffer, bufferSize));
+			free(buffer);
+			return result;
+		}
+#else
+		const char* profileDirA;
+		if (profileDirA = std::getenv("userprofile")) // STL way succeed
+			return bfs::path(profileDirA) / "vcmi";
+#endif
+		else
+			return "."; // Every thing failed, return current directory.
+	}
+	else
+		return bfs::path(profileDir) / "vcmi";
 
 
-std::string VCMIDirs::serverPath() const
-{
-	return libraryPath() + "\\" + "VCMI_server.exe";
+	//return dataPaths()[0] ???;
 }
 }
+bfs::path VCMIDirsWIN32::oldUserSavePath() const { return userDataPath() / "Games"; }
 
 
-std::vector<std::string> VCMIDirs::dataPaths() const
-{
-	return std::vector<std::string>(1, ".");
-}
+bfs::path VCMIDirsWIN32::userCachePath() const { return userDataPath(); }
+bfs::path VCMIDirsWIN32::userConfigPath() const { return userDataPath() / "config"; }
 
 
-std::string VCMIDirs::libraryName(std::string basename) const
+std::vector<bfs::path> VCMIDirsWIN32::dataPaths() const
 {
 {
-	return basename + ".dll";
+	return std::vector<bfs::path>(1, bfs::path("."));
 }
 }
 
 
-#elif defined(__APPLE__)
+bfs::path VCMIDirsWIN32::clientPath() const { return binaryPath() / "VCMI_client.exe"; }
+bfs::path VCMIDirsWIN32::serverPath() const { return binaryPath() / "VCMI_server.exe"; }
 
 
-std::string VCMIDirs::userCachePath() const
-{
-	return userDataPath();
-}
+bfs::path VCMIDirsWIN32::libraryPath() const { return "."; }
+bfs::path VCMIDirsWIN32::binaryPath() const { return ".";  }
 
 
-std::string VCMIDirs::userConfigPath() const
+std::string VCMIDirsWIN32::genHelpString() const
 {
 {
-	return userDataPath() + "/config";
-}
 
 
-std::string VCMIDirs::userSavePath() const
-{
-	return userDataPath() + "/Games";
+	std::vector<std::string> tempVec;
+	for (const bfs::path& path : dataPaths())
+		tempVec.push_back(path.string());
+	std::string gdStringA = boost::algorithm::join(tempVec, ";");
+
+
+	return
+		"  game data:   " + gdStringA + "\n"
+		"  libraries:   " + libraryPath().string() + "\n"
+		"  server:      " + serverPath().string() + "\n"
+		"\n"
+		"  user data:   " + userDataPath().string() + "\n"
+		"  user cache:  " + userCachePath().string() + "\n"
+		"  user config: " + userConfigPath().string() + "\n"
+		"  user saves:  " + userSavePath().string() + "\n"; // Should end without new-line?
 }
 }
 
 
-std::string VCMIDirs::userDataPath() const
+std::string VCMIDirsWIN32::libraryName(const std::string& basename) const { return basename + ".dll"; }
+#elif defined(VCMI_UNIX)
+class IVCMIDirsUNIX : public IVCMIDirs
 {
 {
-	// This is Cocoa code that should be normally used to get path to Application Support folder but can't use it here for now...
-	// NSArray* urls = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask];
-	// UserPath = path([urls[0] path] + "/vcmi").string();
+	public:
+		boost::filesystem::path clientPath() const override;
+		boost::filesystem::path serverPath() const override;
 
 
-	// ...so here goes a bit of hardcode instead
-	std::string home_dir = ".";
-	if (getenv("HOME") != nullptr )
-		home_dir = getenv("HOME");
+		std::string genHelpString() const override;
+};
 
 
-	return boost::filesystem::path(home_dir + "/Library/Application Support/vcmi").string();
-}
+bfs::path IVCMIDirsUNIX::clientPath() const { return binaryPath() / "vcmiclient"; }
+bfs::path IVCMIDirsUNIX::serverPath() const { return binaryPath() / "vcmiserver"; }
 
 
-std::string VCMIDirs::libraryPath() const
+std::string IVCMIDirsUNIX::genHelpString() const
 {
 {
-	return ".";
-}
+	std::vector<std::string> tempVec;
+	for (const bfs::path& path : dataPaths())
+		tempVec.push_back(path.string());
+	std::string gdStringA = boost::algorithm::join(tempVec, ":");
 
 
-std::string VCMIDirs::clientPath() const
-{
-	return "./vcmiclient";
-}
 
 
-std::string VCMIDirs::serverPath() const
-{
-	return "./vcmiserver";
+	return
+		"  game data:   " + gdStringA + "\n"
+		"  libraries:   " + libraryPath().string() + "\n"
+		"  server:      " + serverPath().string() + "\n"
+		"\n"
+		"  user data:   " + userDataPath().string() + "\n"
+		"  user cache:  " + userCachePath().string() + "\n"
+		"  user config: " + userConfigPath().string() + "\n"
+		"  user saves:  " + userSavePath().string() + "\n"; // Should end without new-line?
 }
 }
 
 
-std::vector<std::string> VCMIDirs::dataPaths() const
+#ifdef VCMI_APPLE
+class VCMIDirsOSX : public IVCMIDirsUNIX
 {
 {
-	return std::vector<std::string>(1, "../Data");
-}
+	public:
+		boost::filesystem::path userDataPath() const override;
+		boost::filesystem::path userCachePath() const override;
+		boost::filesystem::path userConfigPath() const override;
 
 
-std::string VCMIDirs::libraryName(std::string basename) const
-{
-	return "lib" + basename + ".dylib";
-}
+		std::vector<boost::filesystem::path> dataPaths() const override;
 
 
-#else
+		boost::filesystem::path libraryPath() const override;
+		boost::filesystem::path binaryPath() const override;
 
 
-std::string VCMIDirs::libraryName(std::string basename) const
-{
-	return "lib" + basename + ".so";
-}
+		std::string libraryName(const std::string& basename) const override;
 
 
-std::string VCMIDirs::libraryPath() const
+		void init() override;
+};
+
+void VCMIDirsOSX::init()
 {
 {
-	return M_LIB_DIR;
+	// Call base (init dirs)
+	IVCMIDirsUNIX::init();
+
+	auto moveDirIfExists = [](const bfs::path& from, const bfs::path& to)
+	{
+		if (!bfs::is_directory(from))
+			return; // Nothing to do here. Flies away.
+
+		if (bfs::is_empty(from))
+		{
+			bfs::remove(from);
+			return; // Nothing to do here. Flies away.
+		}
+
+		if (!bfs::is_directory(to))
+		{
+			// IVCMIDirs::init() should create all destination directories.
+			// TODO: Log fact, that we shouldn't be here.
+			bfs::create_directory(to);
+		}
+
+		for (bfs::directory_iterator file(from); file != bfs::directory_iterator(); ++file)
+		{
+			const boost::filesystem::path& srcFilePath = file->path();
+			const boost::filesystem::path  dstFilePath = to / srcFilePath.filename();
+
+			// TODO: Aplication should ask user what to do when file exists:
+			// replace/ignore/stop process/replace all/ignore all
+			if (!boost::filesystem::exists(dstFilePath))
+				bfs::rename(srcFilePath, dstFilePath);
+		}
+
+		if (!bfs::is_empty(from)); // TODO: Log warn. Some files not moved. User should try to move files.
+		else
+			bfs::remove(from);
+	};
+
+	moveDirIfExists(userDataPath() / "Games", userSavePath());
 }
 }
 
 
-std::string VCMIDirs::clientPath() const
+bfs::path VCMIDirsOSX::userDataPath() const
 {
 {
-	return std::string(M_BIN_DIR) + "/" + "vcmiclient";
+	// This is Cocoa code that should be normally used to get path to Application Support folder but can't use it here for now...
+	// NSArray* urls = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask];
+	// UserPath = path([urls[0] path] + "/vcmi").string();
+
+	// ...so here goes a bit of hardcode instead
+
+	const char* homeDir = getenv("HOME"); // Should be std::getenv?
+	if (homeDir == nullptr)
+		homeDir = ".";
+	return bfs::path(homeDir) / "Library" / "Application Support" / "vcmi";
 }
 }
+bfs::path VCMIDirsOSX::userCachePath() const { return userDataPath(); }
+bfs::path VCMIDirsOSX::userConfigPath() const { return userDataPath() / "config"; }
 
 
-std::string VCMIDirs::serverPath() const
+std::vector<bfs::path> VCMIDirsOSX::dataPaths() const
 {
 {
-	return std::string(M_BIN_DIR) + "/" + "vcmiserver";
+	return std::vector<bfs::path>(1, "../Data");
 }
 }
 
 
-// $XDG_DATA_HOME, default: $HOME/.local/share
-std::string VCMIDirs::userDataPath() const
+bfs::path VCMIDirsOSX::libraryPath() const { return "."; }
+bfs::path VCMIDirsOSX::binaryPath() const { return "."; }
+
+std::string libraryName(const std::string& basename) { return "lib" + basename + ".dylib"; }
+#elif defined(VCMI_LINUX)
+class VCMIDirsLinux : public IVCMIDirsUNIX
 {
 {
-#ifdef __ANDROID__
-	// on Android HOME will be set to something like /sdcard/data/Android/is.xyz.vcmi/files/
-	return std::string(getenv("HOME"));
-#else
-	if (getenv("XDG_DATA_HOME") != nullptr )
-		return std::string(getenv("XDG_DATA_HOME")) + "/vcmi";
-	if (getenv("HOME") != nullptr )
-		return std::string(getenv("HOME")) + "/.local/share" + "/vcmi";
-	return ".";
-#endif
-}
+public:
+	boost::filesystem::path userDataPath() const override;
+	boost::filesystem::path userCachePath() const override;
+	boost::filesystem::path userConfigPath() const override;
+
+	std::vector<boost::filesystem::path> dataPaths() const override;
 
 
-std::string VCMIDirs::userSavePath() const
+	boost::filesystem::path libraryPath() const override;
+	boost::filesystem::path binaryPath() const override;
+
+	std::string libraryName(const std::string& basename) const override;
+};
+
+bfs::path VCMIDirsLinux::userDataPath() const
 {
 {
-	return userDataPath() + "/Saves";
+	// $XDG_DATA_HOME, default: $HOME/.local/share
+	const char* homeDir;
+	if ((homeDir = getenv("XDG_DATA_HOME")))
+		return homeDir;
+	else if ((homeDir = getenv("HOME")))
+		return bfs::path(homeDir) / ".local" / "share" / "vcmi";
+	else
+		return ".";
 }
 }
-
-// $XDG_CACHE_HOME, default: $HOME/.cache
-std::string VCMIDirs::userCachePath() const
+bfs::path VCMIDirsLinux::userCachePath() const
 {
 {
-#ifdef __ANDROID__
-	return userDataPath() + "/cache";
-#else
-	if (getenv("XDG_CACHE_HOME") != nullptr )
-		return std::string(getenv("XDG_CACHE_HOME")) + "/vcmi";
-	if (getenv("HOME") != nullptr )
-		return std::string(getenv("HOME")) + "/.cache" + "/vcmi";
-	return ".";
-#endif
+	// $XDG_CACHE_HOME, default: $HOME/.cache
+	const char* tempResult;
+	if ((tempResult = getenv("XDG_CACHE_HOME")))
+		return bfs::path(tempResult) / "vcmi";
+	else if ((tempResult = getenv("HOME")))
+		return bfs::path(tempResult) / ".cache" / "vcmi";
+	else
+		return ".";
 }
 }
-
-// $XDG_CONFIG_HOME, default: $HOME/.config
-std::string VCMIDirs::userConfigPath() const
+bfs::path VCMIDirsLinux::userConfigPath() const
 {
 {
-#ifdef __ANDROID__
-	return userDataPath() + "/config";
-#else
-	if (getenv("XDG_CONFIG_HOME") != nullptr )
-		return std::string(getenv("XDG_CONFIG_HOME")) + "/vcmi";
-	if (getenv("HOME") != nullptr )
-		return std::string(getenv("HOME")) + "/.config" + "/vcmi";
-	return ".";
-#endif
+	// $XDG_CONFIG_HOME, default: $HOME/.config
+	const char* tempResult;
+	if ((tempResult = getenv("XDG_CONFIG_HOME")))
+		return bfs::path(tempResult) / "vcmi";
+	else if ((tempResult = getenv("HOME")))
+		return bfs::path(tempResult) / ".config" / "vcmi";
+	else
+		return ".";
 }
 }
 
 
-// $XDG_DATA_DIRS, default: /usr/local/share/:/usr/share/
-std::vector<std::string> VCMIDirs::dataPaths() const
+std::vector<bfs::path> VCMIDirsLinux::dataPaths() const
 {
 {
+	// $XDG_DATA_DIRS, default: /usr/local/share/:/usr/share/
+
 	// construct list in reverse.
 	// construct list in reverse.
 	// in specification first directory has highest priority
 	// in specification first directory has highest priority
 	// in vcmi fs last directory has highest priority
 	// in vcmi fs last directory has highest priority
+	std::vector<bfs::path> ret;
 
 
-	std::vector<std::string> ret;
-#ifdef __ANDROID__
-	ret.push_back(userDataPath());
-#else
-	if (getenv("HOME") != nullptr ) // compatibility, should be removed after 0.96
-		ret.push_back(std::string(getenv("HOME")) + "/.vcmi");
+	const char* tempResult;
 	ret.push_back(M_DATA_DIR);
 	ret.push_back(M_DATA_DIR);
 
 
-	if (getenv("XDG_DATA_DIRS") != nullptr)
+	if ((tempResult = getenv("XDG_DATA_DIRS")) != nullptr)
 	{
 	{
-		std::string dataDirsEnv = getenv("XDG_DATA_DIRS");
+		std::string dataDirsEnv = tempResult;
 		std::vector<std::string> dataDirs;
 		std::vector<std::string> dataDirs;
 		boost::split(dataDirs, dataDirsEnv, boost::is_any_of(":"));
 		boost::split(dataDirs, dataDirsEnv, boost::is_any_of(":"));
 		for (auto & entry : boost::adaptors::reverse(dataDirs))
 		for (auto & entry : boost::adaptors::reverse(dataDirs))
@@ -231,21 +516,61 @@ std::vector<std::string> VCMIDirs::dataPaths() const
 		ret.push_back("/usr/share/");
 		ret.push_back("/usr/share/");
 		ret.push_back("/usr/local/share/");
 		ret.push_back("/usr/local/share/");
 	}
 	}
-#endif
+
 	return ret;
 	return ret;
 }
 }
 
 
-#endif
+bfs::path VCMIDirsLinux::libraryPath() const { return M_LIB_DIR; }
+bfs::path VCMIDirsLinux::binaryPath() const { return M_BIN_DIR; }
 
 
-std::string VCMIDirs::genHelpString() const
+std::string VCMIDirsLinux::libraryName(const std::string& basename) const { return "lib" + basename + ".so"; }
+#ifdef VCMI_ANDROID
+class VCMIDirsAndroid : public VCMIDirsLinux
 {
 {
-	return
-	"  game data:   " + boost::algorithm::join(dataPaths(), ":") + "\n" +
-	"  libraries:   " + libraryPath() + "\n" +
-	"  server:      " + serverPath() + "\n" +
-	"\n" +
-	"  user data:   " + userDataPath() + "\n" +
-	"  user cache:  " + userCachePath() + "\n" +
-	"  user config: " + userConfigPath() + "\n" +
-	"  user saves:  " + userSavePath() + "\n";
+public:
+	boost::filesystem::path userDataPath() const override;
+	boost::filesystem::path userCachePath() const override;
+	boost::filesystem::path userConfigPath() const override;
+
+	std::vector<boost::filesystem::path> dataPaths() const override;
+};
+
+// on Android HOME will be set to something like /sdcard/data/Android/is.xyz.vcmi/files/
+bfs::path VCMIDirsAndroid::userDataPath() const { return getenv("HOME"); }
+bfs::path VCMIDirsAndroid::userCachePath() const { return userDataPath() / "cache"; }
+bfs::path VCMIDirsAndroid::userConfigPath() const { return userDataPath() / "config"; }
+
+std::vector<bfs::path> VCMIDirsAndroid::dataPaths() const
+{
+	return std::vector<bfs::path>(1, userDataPath());
 }
 }
+#endif // VCMI_ANDROID
+#endif // VCMI_APPLE, VCMI_LINUX
+#endif // VCMI_WINDOWS, VCMI_UNIX
+
+// Getters for interfaces are separated for clarity.
+namespace VCMIDirs
+{
+	const IVCMIDirs& get()
+	{
+		#ifdef VCMI_WINDOWS
+			static VCMIDirsWIN32 singleton;
+		#elif defined(VCMI_ANDROID)
+			static VCMIDirsAndroid singleton;
+		#elif defined(VCMI_LINUX)
+			static VCMIDirsLinux singleton;
+		#elif defined(VCMI_APPLE)
+			static VCMIDirsOSX singleton;
+		#endif
+		static bool initialized = false;
+		if (!initialized)
+		{
+			std::locale::global(boost::locale::generator().generate("en_US.UTF-8"));
+			boost::filesystem::path::imbue(std::locale());
+
+			singleton.init();
+			initialized = true;
+		}
+		return singleton;
+	}
+}

+ 44 - 38
lib/VCMIDirs.h

@@ -1,52 +1,58 @@
+/*
+* VCMIDirs.h, part of VCMI engine
+*
+* Authors: listed in file AUTHORS in main folder
+*
+* License: GNU General Public License v2.0 or later
+* Full text of license available in license.txt file, in main folder
+*
+*/
 #pragma once
 #pragma once
 
 
-#include "GameConstants.h"
-
-/*
- * VCMIDirs.h, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-
-/// Where to find the various VCMI files. This is mostly useful for linux. 
-class DLL_LINKAGE VCMIDirs
+class DLL_LINKAGE IVCMIDirs
 {
 {
-public:
-	VCMIDirs();
+	public:
+		// Path to user-specific data directory
+		virtual boost::filesystem::path userDataPath() const = 0;
 
 
-	/// get singleton instance
-	static VCMIDirs & get();
+		// Path to "cache" directory, can be used for any non-essential files
+		virtual boost::filesystem::path userCachePath() const = 0;
 
 
-	/// Path to user-specific data directory
-	std::string userDataPath() const;
+		// Path to writeable directory with user configs
+		virtual boost::filesystem::path userConfigPath() const = 0;
 
 
-	/// Path to "cache" directory, can be used for any non-essential files
-	std::string userCachePath() const;
+		// Path to saved games
+		virtual boost::filesystem::path userSavePath() const;
 
 
-	/// Path to writeable directory with user configs
-	std::string userConfigPath() const;
+		// Paths to global system-wide data directories. First items have higher priority
+		virtual std::vector<boost::filesystem::path> dataPaths() const = 0;
 
 
-	/// Path to saved games
-	std::string userSavePath() const;
+		// Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
+		virtual boost::filesystem::path clientPath() const = 0;
 
 
-	/// Paths to global system-wide data directories. First items have higher priority
-	std::vector<std::string> dataPaths() const;
+		// Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
+		virtual boost::filesystem::path serverPath() const = 0;
 
 
-	/// Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
-	std::string clientPath() const;
+		// Path where vcmi libraries can be found (in AI and Scripting subdirectories)
+		virtual boost::filesystem::path libraryPath() const = 0;
 
 
-	/// Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
-	std::string serverPath() const;
+		// Path where vcmi binaries can be found
+		virtual boost::filesystem::path binaryPath() const = 0;
 
 
-	/// Path where vcmi libraries can be found (in AI and Scripting subdirectories)
-	std::string libraryPath() const;
+		// Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
+		virtual std::string libraryName(const std::string& basename) const = 0;
+		// virtual std::string libraryName(const char* basename) const = 0; ?
+		// virtual std::string libraryName(std::string&& basename) const = 0;?
 
 
-	/// Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
-	std::string libraryName(std::string basename) const;
-
-	std::string genHelpString() const;
+		virtual std::string genHelpString() const = 0;
+		
+		// Creates not existed, but required directories.
+		// Updates directories what change name/path between versions.
+		// Function called automatically.
+		virtual void init();
 };
 };
+
+namespace VCMIDirs
+{
+	extern DLL_LINKAGE const IVCMIDirs& get();
+}

+ 10 - 19
lib/filesystem/CArchiveLoader.cpp

@@ -13,9 +13,9 @@ ArchiveEntry::ArchiveEntry()
 
 
 }
 }
 
 
-CArchiveLoader::CArchiveLoader(const std::string &mountPoint, const std::string & archive):
-    archive(archive),
-    mountPoint(mountPoint)
+CArchiveLoader::CArchiveLoader(std::string _mountPoint, boost::filesystem::path _archive) :
+    archive(std::move(_archive)),
+    mountPoint(std::move(_mountPoint))
 {
 {
 	// Open archive file(.snd, .vid, .lod)
 	// Open archive file(.snd, .vid, .lod)
 	CFileInputStream fileStream(archive);
 	CFileInputStream fileStream(archive);
@@ -25,28 +25,19 @@ CArchiveLoader::CArchiveLoader(const std::string &mountPoint, const std::string
 		return;
 		return;
 
 
 	// Retrieve file extension of archive in uppercase
 	// Retrieve file extension of archive in uppercase
-	CFileInfo fileInfo(archive);
-	std::string ext = fileInfo.getExtension();
-	boost::to_upper(ext);
+	const std::string ext = boost::to_upper_copy(archive.extension().string());
 
 
 	// Init the specific lod container format
 	// Init the specific lod container format
 	if(ext == ".LOD" || ext == ".PAC")
 	if(ext == ".LOD" || ext == ".PAC")
-	{
 		initLODArchive(mountPoint, fileStream);
 		initLODArchive(mountPoint, fileStream);
-	}
 	else if(ext == ".VID")
 	else if(ext == ".VID")
-	{
 		initVIDArchive(mountPoint, fileStream);
 		initVIDArchive(mountPoint, fileStream);
-	}
 	else if(ext == ".SND")
 	else if(ext == ".SND")
-	{
 		initSNDArchive(mountPoint, fileStream);
 		initSNDArchive(mountPoint, fileStream);
-	}
 	else
 	else
-	{
-		throw std::runtime_error("LOD archive format unknown. Cannot deal with " + archive);
-	}
-	logGlobal->traceStream() << ext << "Archive loaded, " << entries.size() << " files found";
+		throw std::runtime_error("LOD archive format unknown. Cannot deal with " + archive.string());
+
+	logGlobal->traceStream() << ext << "Archive \""<<archive.filename()<<"\" loaded (" << entries.size() << " files found).";
 }
 }
 
 
 void CArchiveLoader::initLODArchive(const std::string &mountPoint, CFileInputStream & fileStream)
 void CArchiveLoader::initLODArchive(const std::string &mountPoint, CFileInputStream & fileStream)
@@ -61,7 +52,7 @@ void CArchiveLoader::initLODArchive(const std::string &mountPoint, CFileInputStr
 	fileStream.seek(0x5c);
 	fileStream.seek(0x5c);
 
 
 	// Insert entries to list
 	// Insert entries to list
-	for(ui32 i = 0; i < totalFiles; i++)
+	for(ui32 i = 0; i < totalFiles; ++i)
 	{
 	{
 		char filename[16];
 		char filename[16];
 		reader.read(reinterpret_cast<ui8*>(filename), 16);
 		reader.read(reinterpret_cast<ui8*>(filename), 16);
@@ -90,7 +81,7 @@ void CArchiveLoader::initVIDArchive(const std::string &mountPoint, CFileInputStr
 	std::set<int> offsets;
 	std::set<int> offsets;
 
 
 	// Insert entries to list
 	// Insert entries to list
-	for(ui32 i = 0; i < totalFiles; i++)
+	for(ui32 i = 0; i < totalFiles; ++i)
 	{
 	{
 		char filename[40];
 		char filename[40];
 		reader.read(reinterpret_cast<ui8*>(filename), 40);
 		reader.read(reinterpret_cast<ui8*>(filename), 40);
@@ -122,7 +113,7 @@ void CArchiveLoader::initSNDArchive(const std::string &mountPoint, CFileInputStr
 	ui32 totalFiles = reader.readUInt32();
 	ui32 totalFiles = reader.readUInt32();
 
 
 	// Insert entries to list
 	// Insert entries to list
-	for(ui32 i = 0; i < totalFiles; i++)
+	for(ui32 i = 0; i < totalFiles; ++i)
 	{
 	{
 		char filename[40];
 		char filename[40];
 		reader.read(reinterpret_cast<ui8*>(filename), 40);
 		reader.read(reinterpret_cast<ui8*>(filename), 40);

+ 2 - 2
lib/filesystem/CArchiveLoader.h

@@ -55,7 +55,7 @@ public:
 	 *
 	 *
 	 * @throws std::runtime_error if the archive wasn't found or if the archive isn't supported
 	 * @throws std::runtime_error if the archive wasn't found or if the archive isn't supported
 	 */
 	 */
-	explicit CArchiveLoader(const std::string & mountPoint, const std::string & archive);
+	CArchiveLoader(std::string mountPoint, boost::filesystem::path archive);
 
 
 	/// Interface implementation
 	/// Interface implementation
 	/// @see ISimpleResourceLoader
 	/// @see ISimpleResourceLoader
@@ -87,7 +87,7 @@ private:
 	void initSNDArchive(const std::string &mountPoint, CFileInputStream & fileStream);
 	void initSNDArchive(const std::string &mountPoint, CFileInputStream & fileStream);
 
 
 	/** The file path to the archive which is scanned and indexed. */
 	/** The file path to the archive which is scanned and indexed. */
-	std::string archive;
+	boost::filesystem::path archive;
 
 
 	std::string mountPoint;
 	std::string mountPoint;
 
 

+ 15 - 14
lib/filesystem/CFileInfo.cpp

@@ -41,17 +41,17 @@ std::string CFileInfo::getPath() const
 std::string CFileInfo::getExtension() const
 std::string CFileInfo::getExtension() const
 {
 {
 	// Get position of file extension dot
 	// Get position of file extension dot
-	size_t dotPos = name.find_last_of("/.");
+	size_t dotPos = name.find_last_of('.');
 
 
-	if(dotPos != std::string::npos && name[dotPos] == '.')
+	if(dotPos != std::string::npos)
 		return name.substr(dotPos);
 		return name.substr(dotPos);
-	else
-		return "";
+
+	return "";
 }
 }
 
 
 std::string CFileInfo::getFilename() const
 std::string CFileInfo::getFilename() const
 {
 {
-	size_t found = name.find_last_of("/\\");
+	const size_t found = name.find_last_of("/\\");
 	return name.substr(found + 1);
 	return name.substr(found + 1);
 }
 }
 
 
@@ -60,9 +60,9 @@ std::string CFileInfo::getStem() const
 	std::string rslt = name;
 	std::string rslt = name;
 
 
 	// Remove file extension
 	// Remove file extension
-	size_t dotPos = name.find_last_of("/.");
+	const size_t dotPos = name.find_last_of('.');
 
 
-	if(dotPos != std::string::npos && name[dotPos] == '.')
+	if(dotPos != std::string::npos)
 		rslt.erase(dotPos);
 		rslt.erase(dotPos);
 
 
 	return rslt;
 	return rslt;
@@ -70,18 +70,19 @@ std::string CFileInfo::getStem() const
 
 
 std::string CFileInfo::getBaseName() const
 std::string CFileInfo::getBaseName() const
 {
 {
-	size_t begin = name.find_last_of("/");
-	size_t end = name.find_last_of("/.");
-
-	if(end != std::string::npos && name[end] == '/')
-		end = std::string::npos;
+	size_t begin = name.find_last_of("/\\");
+	size_t end = name.find_last_of(".");
 
 
 	if(begin == std::string::npos)
 	if(begin == std::string::npos)
 		begin = 0;
 		begin = 0;
 	else
 	else
-		begin++;
+		++begin;
+	
+	if (end < begin)
+		end = std::string::npos;
 
 
-	return name.substr(begin, end - begin);
+	size_t len = (end == std::string::npos ? std::string::npos : end - begin);
+	return name.substr(begin, len);
 }
 }
 
 
 EResType::Type CFileInfo::getType() const
 EResType::Type CFileInfo::getType() const

+ 4 - 6
lib/filesystem/CFileInputStream.cpp

@@ -3,7 +3,7 @@
 
 
 #include "CFileInfo.h"
 #include "CFileInfo.h"
 
 
-CFileInputStream::CFileInputStream(const std::string & file, si64 start, si64 size)
+CFileInputStream::CFileInputStream(const boost::filesystem::path & file, si64 start, si64 size)
 {
 {
 	open(file, start, size);
 	open(file, start, size);
 }
 }
@@ -18,14 +18,12 @@ CFileInputStream::~CFileInputStream()
 	fileStream.close();
 	fileStream.close();
 }
 }
 
 
-void CFileInputStream::open(const std::string & file, si64 start, si64 size)
+void CFileInputStream::open(const boost::filesystem::path & file, si64 start, si64 size)
 {
 {
-	fileStream.open(file.c_str(), std::ios::in | std::ios::binary);
+	fileStream.open(file, std::ios::in | std::ios::binary);
 
 
 	if (fileStream.fail())
 	if (fileStream.fail())
-	{
-		throw std::runtime_error("File " + file + " isn't available.");
-	}
+		throw std::runtime_error("File " + file.string() + " isn't available.");
 
 
 	dataStart = start;
 	dataStart = start;
 	dataSize = size;
 	dataSize = size;

+ 3 - 3
lib/filesystem/CFileInputStream.h

@@ -25,7 +25,7 @@ public:
 	 *
 	 *
 	 * @see CFileInputStream::open
 	 * @see CFileInputStream::open
 	 */
 	 */
-	CFileInputStream(const std::string & file, si64 start=0, si64 size=0);
+	CFileInputStream(const boost::filesystem::path & file, si64 start = 0, si64 size = 0);
 
 
 	/**
 	/**
 	 * C-tor. Opens the specified file.
 	 * C-tor. Opens the specified file.
@@ -88,11 +88,11 @@ private:
 	 *
 	 *
 	 * @throws std::runtime_error if file wasn't found
 	 * @throws std::runtime_error if file wasn't found
 	 */
 	 */
-	void open(const std::string & file, si64 start, si64 size);
+	void open(const boost::filesystem::path & file, si64 start, si64 size);
 
 
 	si64 dataStart;
 	si64 dataStart;
 	si64 dataSize;
 	si64 dataSize;
 
 
 	/** Native c++ input file stream object. */
 	/** Native c++ input file stream object. */
-	std::ifstream fileStream;
+	boost::filesystem::ifstream fileStream;
 };
 };

+ 56 - 30
lib/filesystem/CFilesystemLoader.cpp

@@ -4,9 +4,11 @@
 #include "CFileInfo.h"
 #include "CFileInfo.h"
 #include "CFileInputStream.h"
 #include "CFileInputStream.h"
 
 
-CFilesystemLoader::CFilesystemLoader(const std::string &mountPoint, const std::string & baseDirectory, size_t depth, bool initial):
-    baseDirectory(baseDirectory),
-    mountPoint(mountPoint),
+namespace bfs = boost::filesystem;
+
+CFilesystemLoader::CFilesystemLoader(std::string _mountPoint, bfs::path baseDirectory, size_t depth, bool initial):
+    baseDirectory(std::move(baseDirectory)),
+	mountPoint(std::move(_mountPoint)),
     fileList(listFiles(mountPoint, depth, initial))
     fileList(listFiles(mountPoint, depth, initial))
 {
 {
 	logGlobal->traceStream() << "Filesystem loaded, " << fileList.size() << " files found";
 	logGlobal->traceStream() << "Filesystem loaded, " << fileList.size() << " files found";
@@ -16,7 +18,7 @@ std::unique_ptr<CInputStream> CFilesystemLoader::load(const ResourceID & resourc
 {
 {
 	assert(fileList.count(resourceName));
 	assert(fileList.count(resourceName));
 
 
-	std::unique_ptr<CInputStream> stream(new CFileInputStream(baseDirectory + '/' + fileList.at(resourceName)));
+	std::unique_ptr<CInputStream> stream(new CFileInputStream(baseDirectory / fileList.at(resourceName)));
 	return stream;
 	return stream;
 }
 }
 
 
@@ -34,7 +36,7 @@ boost::optional<std::string> CFilesystemLoader::getResourceName(const ResourceID
 {
 {
 	assert(existsResource(resourceName));
 	assert(existsResource(resourceName));
 
 
-	return baseDirectory + '/' + fileList.at(resourceName);
+	return (baseDirectory / fileList.at(resourceName)).string();
 }
 }
 
 
 std::unordered_set<ResourceID> CFilesystemLoader::getFilteredFiles(std::function<bool(const ResourceID &)> filter) const
 std::unordered_set<ResourceID> CFilesystemLoader::getFilteredFiles(std::function<bool(const ResourceID &)> filter) const
@@ -45,7 +47,8 @@ std::unordered_set<ResourceID> CFilesystemLoader::getFilteredFiles(std::function
 	{
 	{
 		if (filter(file.first))
 		if (filter(file.first))
 			foundID.insert(file.first);
 			foundID.insert(file.first);
-	}	return foundID;
+	}
+	return foundID;
 }
 }
 
 
 bool CFilesystemLoader::createResource(std::string filename, bool update)
 bool CFilesystemLoader::createResource(std::string filename, bool update)
@@ -65,7 +68,7 @@ bool CFilesystemLoader::createResource(std::string filename, bool update)
 
 
 	if (!update)
 	if (!update)
 	{
 	{
-		std::ofstream newfile (baseDirectory + "/" + filename);
+		bfs::ofstream newfile(baseDirectory / filename);
 		if (!newfile.good())
 		if (!newfile.good())
 			return false;
 			return false;
 	}
 	}
@@ -73,49 +76,72 @@ bool CFilesystemLoader::createResource(std::string filename, bool update)
 	return true;
 	return true;
 }
 }
 
 
-std::unordered_map<ResourceID, std::string> CFilesystemLoader::listFiles(const std::string &mountPoint, size_t depth, bool initial) const
+std::unordered_map<ResourceID, bfs::path> CFilesystemLoader::listFiles(const std::string &mountPoint, size_t depth, bool initial) const
 {
 {
-	std::set<EResType::Type> initialTypes;
-	initialTypes.insert(EResType::DIRECTORY);
-	initialTypes.insert(EResType::TEXT);
-	initialTypes.insert(EResType::ARCHIVE_LOD);
-	initialTypes.insert(EResType::ARCHIVE_VID);
-	initialTypes.insert(EResType::ARCHIVE_SND);
-	initialTypes.insert(EResType::ARCHIVE_ZIP);
+	static const EResType::Type initArray[] = {
+		EResType::DIRECTORY,
+		EResType::TEXT,
+		EResType::ARCHIVE_LOD,
+		EResType::ARCHIVE_VID,
+		EResType::ARCHIVE_SND,
+		EResType::ARCHIVE_ZIP };
+	static const std::set<EResType::Type> initialTypes(initArray, initArray + ARRAY_COUNT(initArray));
 
 
-	assert(boost::filesystem::is_directory(baseDirectory));
-	std::unordered_map<ResourceID, std::string> fileList;
+	assert(bfs::is_directory(baseDirectory));
+	std::unordered_map<ResourceID, bfs::path> fileList;
 
 
-	std::vector<std::string> path;//vector holding relative path to our file
+	std::vector<bfs::path> path; //vector holding relative path to our file
 
 
-	boost::filesystem::recursive_directory_iterator enddir;
-	boost::filesystem::recursive_directory_iterator it(baseDirectory, boost::filesystem::symlink_option::recurse);
+	bfs::recursive_directory_iterator enddir;
+	bfs::recursive_directory_iterator it(baseDirectory, bfs::symlink_option::recurse);
 
 
 	for(; it != enddir; ++it)
 	for(; it != enddir; ++it)
 	{
 	{
 		EResType::Type type;
 		EResType::Type type;
 
 
-		if (boost::filesystem::is_directory(it->status()))
+		if (bfs::is_directory(it->status()))
 		{
 		{
-			path.resize(it.level()+1);
-			path.back() = it->path().leaf().string();
+			path.resize(it.level() + 1);
+			path.back() = it->path().filename();
 			// don't iterate into directory if depth limit reached
 			// don't iterate into directory if depth limit reached
 			it.no_push(depth <= it.level());
 			it.no_push(depth <= it.level());
 
 
 			type = EResType::DIRECTORY;
 			type = EResType::DIRECTORY;
 		}
 		}
 		else
 		else
-			type = EResTypeHelper::getTypeFromExtension(boost::filesystem::extension(*it));
+			type = EResTypeHelper::getTypeFromExtension(it->path().extension().string());
 
 
 		if (!initial || vstd::contains(initialTypes, type))
 		if (!initial || vstd::contains(initialTypes, type))
 		{
 		{
 			//reconstruct relative filename (not possible via boost AFAIK)
 			//reconstruct relative filename (not possible via boost AFAIK)
-			std::string filename;
-			for (size_t i=0; i<it.level() && i<path.size(); i++)
-				filename += path[i] + '/';
-			filename += it->path().leaf().string();
-
-			fileList[ResourceID(mountPoint + filename, type)] = filename;
+			bfs::path filename;
+			const size_t iterations = std::min((size_t)it.level(), path.size());
+			if (iterations)
+			{
+				filename = path.front();
+				for (size_t i = 1; i < iterations; ++i)
+					filename /= path[i];
+				filename /= it->path().filename();
+			}
+			else
+				filename = it->path().filename();
+
+			std::string resName;
+			if (bfs::path::preferred_separator != '/')
+			{
+				// resource names are using UNIX slashes (/)
+				resName.reserve(resName.size() + filename.native().size());
+				resName = mountPoint;
+				for (const char c : filename.string())
+					if (c != bfs::path::preferred_separator)
+						resName.push_back(c);
+					else
+						resName.push_back('/');
+			}
+			else
+				resName = mountPoint + filename.string();
+
+			fileList[ResourceID(resName, type)] = std::move(filename);
 		}
 		}
 	}
 	}
 
 

+ 5 - 5
lib/filesystem/CFilesystemLoader.h

@@ -30,7 +30,7 @@ public:
 	 *
 	 *
 	 * @throws std::runtime_error if the base directory is not a directory or if it is not available
 	 * @throws std::runtime_error if the base directory is not a directory or if it is not available
 	 */
 	 */
-	explicit CFilesystemLoader(const std::string & mountPoint, const std::string & baseDirectory, size_t depth = 16, bool initial = false);
+	explicit CFilesystemLoader(std::string mountPoint, boost::filesystem::path baseDirectory, size_t depth = 16, bool initial = false);
 
 
 	/// Interface implementation
 	/// Interface implementation
 	/// @see ISimpleResourceLoader
 	/// @see ISimpleResourceLoader
@@ -39,11 +39,11 @@ public:
 	std::string getMountPoint() const override;
 	std::string getMountPoint() const override;
 	bool createResource(std::string filename, bool update = false) override;
 	bool createResource(std::string filename, bool update = false) override;
 	boost::optional<std::string> getResourceName(const ResourceID & resourceName) const override;
 	boost::optional<std::string> getResourceName(const ResourceID & resourceName) const override;
-	std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const;
+	std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const override;
 
 
 private:
 private:
 	/** The base directory which is scanned and indexed. */
 	/** The base directory which is scanned and indexed. */
-	std::string baseDirectory;
+	boost::filesystem::path baseDirectory;
 
 
 	std::string mountPoint;
 	std::string mountPoint;
 
 
@@ -51,7 +51,7 @@ private:
 	 * key = ResourceID for resource loader
 	 * key = ResourceID for resource loader
 	 * value = name that can be used to access file
 	 * value = name that can be used to access file
 	*/
 	*/
-	std::unordered_map<ResourceID, std::string> fileList;
+	std::unordered_map<ResourceID, boost::filesystem::path> fileList;
 
 
 	/**
 	/**
 	 * Returns a list of pathnames denoting the files in the directory denoted by this pathname.
 	 * Returns a list of pathnames denoting the files in the directory denoted by this pathname.
@@ -62,5 +62,5 @@ private:
 	 * @return a list of pathnames denoting the files and directories in the directory denoted by this pathname
 	 * @return a list of pathnames denoting the files and directories in the directory denoted by this pathname
 	 * The array will be empty if the directory is empty. Ptr is null if the directory doesn't exist or if it isn't a directory.
 	 * The array will be empty if the directory is empty. Ptr is null if the directory doesn't exist or if it isn't a directory.
 	 */
 	 */
-	std::unordered_map<ResourceID, std::string> listFiles(const std::string &mountPoint, size_t depth, bool initial) const;
+	std::unordered_map<ResourceID, boost::filesystem::path> listFiles(const std::string &mountPoint, size_t depth, bool initial) const;
 };
 };

+ 2 - 2
lib/filesystem/Filesystem.cpp

@@ -69,7 +69,7 @@ void CFilesystemGenerator::loadDirectory(const std::string &mountPoint, const Js
 	std::string URI = prefix + config["path"].String();
 	std::string URI = prefix + config["path"].String();
 	int depth = 16;
 	int depth = 16;
 	if (!config["depth"].isNull())
 	if (!config["depth"].isNull())
-		depth = config["depth"].Float();
+		depth = (int)config["depth"].Float();
 
 
 	ResourceID resID(URI, EResType::DIRECTORY);
 	ResourceID resID(URI, EResType::DIRECTORY);
 
 
@@ -130,7 +130,7 @@ ISimpleResourceLoader * CResourceHandler::createInitial()
 			auto filename = loader->getResourceName(ID);
 			auto filename = loader->getResourceName(ID);
 			if (filename)
 			if (filename)
 			{
 			{
-				auto dir = new CFilesystemLoader(URI + "/", *filename, depth, true);
+				auto dir = new CFilesystemLoader(URI + '/', *filename, depth, true);
 				initialLoader->addLoader(dir, false);
 				initialLoader->addLoader(dir, false);
 			}
 			}
 		}
 		}

+ 8 - 6
lib/int3.h

@@ -94,11 +94,11 @@ public:
 	}
 	}
 
 
 	//returns squared distance on Oxy plane (z coord is not used)
 	//returns squared distance on Oxy plane (z coord is not used)
-	si32 dist2dSQ(const int3 & o) const
+	ui32 dist2dSQ(const int3 & o) const
 	{
 	{
 		const si32 dx = (x - o.x);
 		const si32 dx = (x - o.x);
 		const si32 dy = (y - o.y);
 		const si32 dy = (y - o.y);
-		return dx*dx + dy*dy;
+		return (ui32)(dx*dx) + (ui32)(dy*dy);
 	}
 	}
 	//returns distance on Oxy plane (z coord is not used)
 	//returns distance on Oxy plane (z coord is not used)
 	double dist2d(const int3 & o) const
 	double dist2d(const int3 & o) const
@@ -157,15 +157,17 @@ struct ShashInt3
 static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),
 static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),
 	int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) };
 	int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) };
 
 
-//FIXME: make sure it's <int3> container and not just any
 template<typename Container>
 template<typename Container>
 int3 findClosestTile (Container & container, int3 dest)
 int3 findClosestTile (Container & container, int3 dest)
 {
 {
-	int3 result(-1,-1,-1);
+	static_assert(std::is_same<typename Container::value_type, int3>::value,
+		"findClosestTile requires <int3> container.");
+
+	int3 result(-1, -1, -1);
 	ui32 distance = std::numeric_limits<ui32>::max();
 	ui32 distance = std::numeric_limits<ui32>::max();
-	for (int3 tile : container)
+	for (const int3& tile : container)
 	{
 	{
-		ui32 currentDistance = dest.dist2dSQ(tile);
+		const ui32 currentDistance = dest.dist2dSQ(tile);
 		if (currentDistance < distance)
 		if (currentDistance < distance)
 		{
 		{
 			result = tile;
 			result = tile;

+ 8 - 16
lib/logging/CBasicLogConfigurator.cpp

@@ -3,11 +3,8 @@
 
 
 #include "../CConfigHandler.h"
 #include "../CConfigHandler.h"
 
 
-CBasicLogConfigurator::CBasicLogConfigurator(const std::string & filePath, CConsoleHandler * console) : filePath(filePath),
-	console(console), appendToLogFile(false)
-{
-
-}
+CBasicLogConfigurator::CBasicLogConfigurator(boost::filesystem::path filePath, CConsoleHandler * const console) :
+	filePath(std::move(filePath)), console(console), appendToLogFile(false) {}
 
 
 void CBasicLogConfigurator::configureDefault()
 void CBasicLogConfigurator::configureDefault()
 {
 {
@@ -21,7 +18,8 @@ void CBasicLogConfigurator::configure()
 	try
 	try
 	{
 	{
 		const JsonNode & loggingNode = settings["logging"];
 		const JsonNode & loggingNode = settings["logging"];
-		if(loggingNode.isNull()) throw std::runtime_error("Settings haven't been loaded.");
+		if(loggingNode.isNull())
+			throw std::runtime_error("Settings haven't been loaded.");
 
 
 		// Configure loggers
 		// Configure loggers
 		const JsonNode & loggers = loggingNode["loggers"];
 		const JsonNode & loggers = loggingNode["loggers"];
@@ -87,7 +85,7 @@ void CBasicLogConfigurator::configure()
 	logGlobal->infoStream() << "Initialized logging system based on settings successfully.";
 	logGlobal->infoStream() << "Initialized logging system based on settings successfully.";
 }
 }
 
 
-ELogLevel::ELogLevel CBasicLogConfigurator::getLogLevel(const std::string & level) const
+ELogLevel::ELogLevel CBasicLogConfigurator::getLogLevel(const std::string & level)
 {
 {
 	static const std::map<std::string, ELogLevel::ELogLevel> levelMap = boost::assign::map_list_of
 	static const std::map<std::string, ELogLevel::ELogLevel> levelMap = boost::assign::map_list_of
 			("trace", ELogLevel::TRACE)
 			("trace", ELogLevel::TRACE)
@@ -95,18 +93,15 @@ ELogLevel::ELogLevel CBasicLogConfigurator::getLogLevel(const std::string & leve
 			("info", ELogLevel::INFO)
 			("info", ELogLevel::INFO)
 			("warn", ELogLevel::WARN)
 			("warn", ELogLevel::WARN)
 			("error", ELogLevel::ERROR);
 			("error", ELogLevel::ERROR);
+	
 	const auto & levelPair = levelMap.find(level);
 	const auto & levelPair = levelMap.find(level);
 	if(levelPair != levelMap.end())
 	if(levelPair != levelMap.end())
-	{
 		return levelPair->second;
 		return levelPair->second;
-	}
 	else
 	else
-	{
 		throw std::runtime_error("Log level " + level + " unknown.");
 		throw std::runtime_error("Log level " + level + " unknown.");
-	}
 }
 }
 
 
-EConsoleTextColor::EConsoleTextColor CBasicLogConfigurator::getConsoleColor(const std::string & colorName) const
+EConsoleTextColor::EConsoleTextColor CBasicLogConfigurator::getConsoleColor(const std::string & colorName)
 {
 {
 	static const std::map<std::string, EConsoleTextColor::EConsoleTextColor> colorMap = boost::assign::map_list_of
 	static const std::map<std::string, EConsoleTextColor::EConsoleTextColor> colorMap = boost::assign::map_list_of
 			("default", EConsoleTextColor::DEFAULT)
 			("default", EConsoleTextColor::DEFAULT)
@@ -117,13 +112,10 @@ EConsoleTextColor::EConsoleTextColor CBasicLogConfigurator::getConsoleColor(cons
 			("white", EConsoleTextColor::WHITE)
 			("white", EConsoleTextColor::WHITE)
 			("gray", EConsoleTextColor::GRAY)
 			("gray", EConsoleTextColor::GRAY)
 			("teal", EConsoleTextColor::TEAL);
 			("teal", EConsoleTextColor::TEAL);
+
 	const auto & colorPair = colorMap.find(colorName);
 	const auto & colorPair = colorMap.find(colorName);
 	if(colorPair != colorMap.end())
 	if(colorPair != colorMap.end())
-	{
 		return colorPair->second;
 		return colorPair->second;
-	}
 	else
 	else
-	{
 		throw std::runtime_error("Color " + colorName + " unknown.");
 		throw std::runtime_error("Color " + colorName + " unknown.");
-	}
 }
 }

+ 9 - 6
lib/logging/CBasicLogConfigurator.h

@@ -22,7 +22,7 @@ class JsonNode;
 class DLL_LINKAGE CBasicLogConfigurator
 class DLL_LINKAGE CBasicLogConfigurator
 {
 {
 public:
 public:
-	CBasicLogConfigurator(const std::string & filePath, CConsoleHandler * console);
+	CBasicLogConfigurator(boost::filesystem::path filePath, CConsoleHandler * const console);
 
 
 	/// Configures the logging system by parsing the logging settings. It adds the console target and the file target to the global logger.
 	/// Configures the logging system by parsing the logging settings. It adds the console target and the file target to the global logger.
 	/// Doesn't throw, but logs on success or fault.
 	/// Doesn't throw, but logs on success or fault.
@@ -30,12 +30,15 @@ public:
 
 
 	/// Configures a default logging system by adding the console target and the file target to the global logger.
 	/// Configures a default logging system by adding the console target and the file target to the global logger.
 	void configureDefault();
 	void configureDefault();
-
 private:
 private:
-	ELogLevel::ELogLevel getLogLevel(const std::string & level) const;
-	EConsoleTextColor::EConsoleTextColor getConsoleColor(const std::string & colorName) const;
-
-	std::string filePath;
+	// Gets ELogLevel enum from string. (Should be moved to CLogger as a separate function?)
+	// Throws: std::runtime_error
+	static ELogLevel::ELogLevel getLogLevel(const std::string & level);
+	// Gets EConsoleTextColor enum from strings. (Should be moved to CLogger as a separate function?)
+	// Throws: std::runtime_error
+	static EConsoleTextColor::EConsoleTextColor getConsoleColor(const std::string & colorName);
+
+	boost::filesystem::path filePath;
 	CConsoleHandler * console;
 	CConsoleHandler * console;
 	bool appendToLogFile;
 	bool appendToLogFile;
 };
 };

+ 93 - 221
lib/logging/CLogger.cpp

@@ -1,46 +1,51 @@
-#ifdef __ANDROID__
-#include <android/log.h>
-#endif
-
 #include "StdInc.h"
 #include "StdInc.h"
 #include "CLogger.h"
 #include "CLogger.h"
 
 
+#ifdef VCMI_ANDROID
+#include <android/log.h>
+
+namespace ELogLevel
+{
+	int toAndroid(ELogLevel logLevel)
+	{
+		switch (logLevel)
+		{
+			case TRACE: return ANDROID_LOG_VERBOSE;
+			case DEBUG: return ANDROID_LOG_DEBUG;
+			case INFO:  return ANDROID_LOG_INFO;
+			case WARN:  return ANDROID_LOG_WARN;
+			case ERROR: return ANDROID_LOG_ERROR;
+			default:;
+		}
+		return ANDROID_LOG_UNKNOWN;
+	}
+}
+#endif
+
 const std::string CLoggerDomain::DOMAIN_GLOBAL = "global";
 const std::string CLoggerDomain::DOMAIN_GLOBAL = "global";
 
 
-CLoggerDomain::CLoggerDomain(const std::string & name) : name(name)
+CLoggerDomain::CLoggerDomain(std::string name) : name(std::move(name))
 {
 {
-	if(name.empty()) throw std::runtime_error("Logger domain cannot be empty.");
+	if (this->name.empty())
+		throw std::runtime_error("Logger domain cannot be empty.");
 }
 }
 
 
 CLoggerDomain CLoggerDomain::getParent() const
 CLoggerDomain CLoggerDomain::getParent() const
 {
 {
-	if(isGlobalDomain()) return *this;
+	if(isGlobalDomain())
+		return *this;
 
 
-	size_t pos = name.find_last_of(".");
+	const size_t pos = name.find_last_of(".");
 	if(pos != std::string::npos)
 	if(pos != std::string::npos)
-	{
 		return CLoggerDomain(name.substr(0, pos));
 		return CLoggerDomain(name.substr(0, pos));
-	}
-	else
-	{
-		return CLoggerDomain(DOMAIN_GLOBAL);
-	}
+	return CLoggerDomain(DOMAIN_GLOBAL);
 }
 }
 
 
-bool CLoggerDomain::isGlobalDomain() const
-{
-	return name == DOMAIN_GLOBAL;
-}
+bool CLoggerDomain::isGlobalDomain() const { return name == DOMAIN_GLOBAL; }
 
 
-std::string CLoggerDomain::getName() const
-{
-	return name;
-}
+const std::string& CLoggerDomain::getName() const { return name; }
 
 
-CLoggerStream::CLoggerStream(const CLogger & logger, ELogLevel::ELogLevel level) : logger(logger), level(level), sbuffer(nullptr)
-{
-
-}
+CLoggerStream::CLoggerStream(const CLogger & logger, ELogLevel::ELogLevel level) : logger(logger), level(level), sbuffer(nullptr) {}
 
 
 CLoggerStream::~CLoggerStream()
 CLoggerStream::~CLoggerStream()
 {
 {
@@ -67,20 +72,14 @@ CLogger * CLogger::getLogger(const CLoggerDomain & domain)
 	TLockGuardRec _(smx);
 	TLockGuardRec _(smx);
 
 
 	CLogger * logger = CLogManager::get().getLogger(domain);
 	CLogger * logger = CLogManager::get().getLogger(domain);
-	if(logger)
-	{
-		return logger;
-	}
-	else
+	if(!logger) // Create new logger
 	{
 	{
 		logger = new CLogger(domain);
 		logger = new CLogger(domain);
 		if(domain.isGlobalDomain())
 		if(domain.isGlobalDomain())
-		{
 			logger->setLevel(ELogLevel::TRACE);
 			logger->setLevel(ELogLevel::TRACE);
-		}
 		CLogManager::get().addLogger(logger);
 		CLogManager::get().addLogger(logger);
-		return logger;
 	}
 	}
+	return logger;
 }
 }
 
 
 CLogger * CLogger::getGlobalLogger()
 CLogger * CLogger::getGlobalLogger()
@@ -102,62 +101,22 @@ CLogger::CLogger(const CLoggerDomain & domain) : domain(domain)
 	}
 	}
 }
 }
 
 
-void CLogger::trace(const std::string & message) const
-{
-	log(ELogLevel::TRACE, message);
-}
-
-CLoggerStream CLogger::traceStream() const
-{
-	return CLoggerStream(*this, ELogLevel::TRACE);
-}
-
-void CLogger::debug(const std::string & message) const
-{
-	log(ELogLevel::DEBUG, message);
-}
-
-CLoggerStream CLogger::debugStream() const
-{
-	return CLoggerStream(*this, ELogLevel::DEBUG);
-}
-
-void CLogger::info(const std::string & message) const
-{
-	log(ELogLevel::INFO, message);
-}
-
-CLoggerStream CLogger::infoStream() const
-{
-	return CLoggerStream(*this, ELogLevel::INFO);
-}
+void CLogger::trace(const std::string & message) const { log(ELogLevel::TRACE, message); }
+void CLogger::debug(const std::string & message) const { log(ELogLevel::DEBUG, message); }
+void CLogger::info(const std::string & message) const { log(ELogLevel::INFO, message); }
+void CLogger::warn(const std::string & message) const { log(ELogLevel::WARN, message); }
+void CLogger::error(const std::string & message) const { log(ELogLevel::ERROR, message); }
 
 
-void CLogger::warn(const std::string & message) const
-{
-	log(ELogLevel::WARN, message);
-}
-
-CLoggerStream CLogger::warnStream() const
-{
-	return CLoggerStream(*this, ELogLevel::WARN);
-}
-
-void CLogger::error(const std::string & message) const
-{
-	log(ELogLevel::ERROR, message);
-}
-
-CLoggerStream CLogger::errorStream() const
-{
-	return CLoggerStream(*this, ELogLevel::ERROR);
-}
+CLoggerStream CLogger::traceStream() const { return CLoggerStream(*this, ELogLevel::TRACE); }
+CLoggerStream CLogger::debugStream() const { return CLoggerStream(*this, ELogLevel::DEBUG); }
+CLoggerStream CLogger::infoStream() const { return CLoggerStream(*this, ELogLevel::INFO); }
+CLoggerStream CLogger::warnStream() const { return CLoggerStream(*this, ELogLevel::WARN); }
+CLoggerStream CLogger::errorStream() const { return CLoggerStream(*this, ELogLevel::ERROR); }
 
 
 void CLogger::log(ELogLevel::ELogLevel level, const std::string & message) const
 void CLogger::log(ELogLevel::ELogLevel level, const std::string & message) const
 {
 {
 	if(getEffectiveLevel() <= level)
 	if(getEffectiveLevel() <= level)
-	{
 		callTargets(LogRecord(domain, level, message));
 		callTargets(LogRecord(domain, level, message));
-	}
 }
 }
 
 
 ELogLevel::ELogLevel CLogger::getLevel() const
 ELogLevel::ELogLevel CLogger::getLevel() const
@@ -169,14 +128,11 @@ ELogLevel::ELogLevel CLogger::getLevel() const
 void CLogger::setLevel(ELogLevel::ELogLevel level)
 void CLogger::setLevel(ELogLevel::ELogLevel level)
 {
 {
 	TLockGuard _(mx);
 	TLockGuard _(mx);
-	if(domain.isGlobalDomain() && level == ELogLevel::NOT_SET) return;
-	this->level = level;
+	if (!domain.isGlobalDomain() || level != ELogLevel::NOT_SET)
+		this->level = level;
 }
 }
 
 
-const CLoggerDomain & CLogger::getDomain() const
-{
-	return domain;
-}
+const CLoggerDomain & CLogger::getDomain() const { return domain; }
 
 
 void CLogger::addTarget(unique_ptr<ILogTarget> && target)
 void CLogger::addTarget(unique_ptr<ILogTarget> && target)
 {
 {
@@ -187,9 +143,8 @@ void CLogger::addTarget(unique_ptr<ILogTarget> && target)
 ELogLevel::ELogLevel CLogger::getEffectiveLevel() const
 ELogLevel::ELogLevel CLogger::getEffectiveLevel() const
 {
 {
 	for(const CLogger * logger = this; logger != nullptr; logger = logger->parent)
 	for(const CLogger * logger = this; logger != nullptr; logger = logger->parent)
-	{
-		if(logger->getLevel() != ELogLevel::NOT_SET) return logger->getLevel();
-	}
+		if(logger->getLevel() != ELogLevel::NOT_SET)
+			return logger->getLevel();
 
 
 	// This shouldn't be reached, as the root logger must have set a log level
 	// This shouldn't be reached, as the root logger must have set a log level
 	return ELogLevel::INFO;
 	return ELogLevel::INFO;
@@ -199,12 +154,8 @@ void CLogger::callTargets(const LogRecord & record) const
 {
 {
 	TLockGuard _(mx);
 	TLockGuard _(mx);
 	for(const CLogger * logger = this; logger != nullptr; logger = logger->parent)
 	for(const CLogger * logger = this; logger != nullptr; logger = logger->parent)
-	{
 		for(auto & target : logger->targets)
 		for(auto & target : logger->targets)
-		{
 			target->write(record);
 			target->write(record);
-		}
-	}
 }
 }
 
 
 void CLogger::clearTargets()
 void CLogger::clearTargets()
@@ -213,26 +164,15 @@ void CLogger::clearTargets()
 	targets.clear();
 	targets.clear();
 }
 }
 
 
-bool CLogger::isDebugEnabled() const
-{
-	return getEffectiveLevel() <= ELogLevel::DEBUG;
-}
-
-bool CLogger::isTraceEnabled() const
-{
-	return getEffectiveLevel() <= ELogLevel::TRACE;
-}
+bool CLogger::isDebugEnabled() const { return getEffectiveLevel() <= ELogLevel::DEBUG; }
+bool CLogger::isTraceEnabled() const { return getEffectiveLevel() <= ELogLevel::TRACE; }
 
 
 CTraceLogger::CTraceLogger(const CLogger * logger, const std::string & beginMessage, const std::string & endMessage)
 CTraceLogger::CTraceLogger(const CLogger * logger, const std::string & beginMessage, const std::string & endMessage)
 	: logger(logger), endMessage(endMessage)
 	: logger(logger), endMessage(endMessage)
 {
 {
-	logger->traceStream() << beginMessage;
-}
-
-CTraceLogger::~CTraceLogger()
-{
-	logger->traceStream() << endMessage;
+	logger->trace(beginMessage);
 }
 }
+CTraceLogger::~CTraceLogger() { logger->trace(std::move(endMessage)); }
 
 
 CLogManager & CLogManager::get()
 CLogManager & CLogManager::get()
 {
 {
@@ -241,17 +181,11 @@ CLogManager & CLogManager::get()
 	return instance;
 	return instance;
 }
 }
 
 
-CLogManager::CLogManager()
-{
-
-}
-
+CLogManager::CLogManager() { }
 CLogManager::~CLogManager()
 CLogManager::~CLogManager()
 {
 {
 	for(auto & i : loggers)
 	for(auto & i : loggers)
-	{
 		delete i.second;
 		delete i.second;
-	}
 }
 }
 
 
 void CLogManager::addLogger(CLogger * logger)
 void CLogManager::addLogger(CLogger * logger)
@@ -265,34 +199,30 @@ CLogger * CLogManager::getLogger(const CLoggerDomain & domain)
 	TLockGuard _(mx);
 	TLockGuard _(mx);
 	auto it = loggers.find(domain.getName());
 	auto it = loggers.find(domain.getName());
 	if(it != loggers.end())
 	if(it != loggers.end())
-	{
 		return it->second;
 		return it->second;
-	}
 	else
 	else
-	{
 		return nullptr;
 		return nullptr;
-	}
 }
 }
 
 
-CLogFormatter::CLogFormatter() : pattern("%m")
+CLogFormatter::CLogFormatter() : CLogFormatter("%m") { }
+
+CLogFormatter::CLogFormatter(const std::string & pattern) : pattern(pattern)
 {
 {
 	boost::posix_time::time_facet * facet = new boost::posix_time::time_facet("%H:%M:%S");
 	boost::posix_time::time_facet * facet = new boost::posix_time::time_facet("%H:%M:%S");
 	dateStream.imbue(std::locale(dateStream.getloc(), facet));
 	dateStream.imbue(std::locale(dateStream.getloc(), facet));
 }
 }
 
 
-CLogFormatter::CLogFormatter(const std::string & pattern)
-{
-	setPattern(pattern);
-}
+CLogFormatter::CLogFormatter(const CLogFormatter & c) : pattern(c.pattern) { }
+CLogFormatter::CLogFormatter(CLogFormatter && m) : pattern(std::move(m.pattern)) { }
 
 
-CLogFormatter::CLogFormatter(const CLogFormatter & other)
+CLogFormatter & CLogFormatter::operator=(const CLogFormatter & c)
 {
 {
-	*this = other;
+	pattern = c.pattern;
+	return *this;
 }
 }
-
-CLogFormatter & CLogFormatter::operator=(const CLogFormatter & other)
+CLogFormatter & CLogFormatter::operator=(CLogFormatter && m)
 {
 {
-	pattern = other.pattern;
+	pattern = std::move(m.pattern);
 	return *this;
 	return *this;
 }
 }
 
 
@@ -336,15 +266,10 @@ std::string CLogFormatter::format(const LogRecord & record) const
 	return message;
 	return message;
 }
 }
 
 
-void CLogFormatter::setPattern(const std::string & pattern)
-{
-	this->pattern = pattern;
-}
+void CLogFormatter::setPattern(const std::string & pattern) { this->pattern = pattern; }
+void CLogFormatter::setPattern(std::string && pattern) { this->pattern = std::move(pattern); }
 
 
-const std::string & CLogFormatter::getPattern() const
-{
-	return pattern;
-}
+const std::string & CLogFormatter::getPattern() const { return pattern; }
 
 
 CColorMapping::CColorMapping()
 CColorMapping::CColorMapping()
 {
 {
@@ -365,30 +290,24 @@ void CColorMapping::setColorFor(const CLoggerDomain & domain, ELogLevel::ELogLev
 
 
 EConsoleTextColor::EConsoleTextColor CColorMapping::getColorFor(const CLoggerDomain & domain, ELogLevel::ELogLevel level) const
 EConsoleTextColor::EConsoleTextColor CColorMapping::getColorFor(const CLoggerDomain & domain, ELogLevel::ELogLevel level) const
 {
 {
-	std::string name = domain.getName();
+	CLoggerDomain currentDomain = domain;
 	while(true)
 	while(true)
 	{
 	{
-		const auto & loggerPair = map.find(name);
+		const auto & loggerPair = map.find(currentDomain.getName());
 		if(loggerPair != map.end())
 		if(loggerPair != map.end())
 		{
 		{
 			const auto & levelMap = loggerPair->second;
 			const auto & levelMap = loggerPair->second;
 			const auto & levelPair = levelMap.find(level);
 			const auto & levelPair = levelMap.find(level);
 			if(levelPair != levelMap.end())
 			if(levelPair != levelMap.end())
-			{
 				return levelPair->second;
 				return levelPair->second;
-			}
 		}
 		}
 
 
-		CLoggerDomain currentDomain(name);
-		if(!currentDomain.isGlobalDomain())
-		{
-			name = currentDomain.getParent().getName();
-		}
-		else
-		{
+		if (currentDomain.isGlobalDomain())
 			break;
 			break;
-		}
+
+		currentDomain = currentDomain.getParent();
 	}
 	}
+
 	throw std::runtime_error("failed to find color for requested domain/level pair");
 	throw std::runtime_error("failed to find color for requested domain/level pair");
 }
 }
 
 
@@ -399,103 +318,56 @@ CLogConsoleTarget::CLogConsoleTarget(CConsoleHandler * console) : console(consol
 
 
 void CLogConsoleTarget::write(const LogRecord & record)
 void CLogConsoleTarget::write(const LogRecord & record)
 {
 {
-	if(threshold > record.level) return;
+	if(threshold > record.level)
+		return;
 
 
 	std::string message = formatter.format(record);
 	std::string message = formatter.format(record);
 
 
-#ifdef __ANDROID__
-	__android_log_print(ANDROID_LOG_INFO, "VCMI", "%s", message.c_str());
+#ifdef VCMI_ANDROID
+	__android_log_write(ELogLevel::toAndroid(record.level), "VCMI", message.c_str());
 #endif
 #endif
 
 
-	bool printToStdErr = record.level >= ELogLevel::WARN;
+	const bool printToStdErr = record.level >= ELogLevel::WARN;
 	if(console)
 	if(console)
 	{
 	{
-		if(coloredOutputEnabled)
-		{
-			console->print(message, true, colorMapping.getColorFor(record.domain, record.level));
-		}
-		else
-		{
-			console->print(message, true, EConsoleTextColor::DEFAULT, printToStdErr);
-		}
+		const EConsoleTextColor::EConsoleTextColor textColor =
+			coloredOutputEnabled ? colorMapping.getColorFor(record.domain, record.level) : EConsoleTextColor::DEFAULT;
+		
+		console->print(message, true, textColor, printToStdErr);
 	}
 	}
 	else
 	else
 	{
 	{
 		TLockGuard _(mx);
 		TLockGuard _(mx);
 		if(printToStdErr)
 		if(printToStdErr)
-		{
 			std::cerr << message << std::endl;
 			std::cerr << message << std::endl;
-		}
 		else
 		else
-		{
 			std::cout << message << std::endl;
 			std::cout << message << std::endl;
-		}
 	}
 	}
 }
 }
 
 
-bool CLogConsoleTarget::isColoredOutputEnabled() const
-{
-	return coloredOutputEnabled;
-}
-
-void CLogConsoleTarget::setColoredOutputEnabled(bool coloredOutputEnabled)
-{
-	this->coloredOutputEnabled = coloredOutputEnabled;
-}
-
-ELogLevel::ELogLevel CLogConsoleTarget::getThreshold() const
-{
-	return threshold;
-}
-
-void CLogConsoleTarget::setThreshold(ELogLevel::ELogLevel threshold)
-{
-	this->threshold = threshold;
-}
-
-const CLogFormatter & CLogConsoleTarget::getFormatter() const
-{
-	return formatter;
-}
+bool CLogConsoleTarget::isColoredOutputEnabled() const { return coloredOutputEnabled; }
+void CLogConsoleTarget::setColoredOutputEnabled(bool coloredOutputEnabled) { this->coloredOutputEnabled = coloredOutputEnabled; }
 
 
-void CLogConsoleTarget::setFormatter(const CLogFormatter & formatter)
-{
-	this->formatter = formatter;
-}
+ELogLevel::ELogLevel CLogConsoleTarget::getThreshold() const { return threshold; }
+void CLogConsoleTarget::setThreshold(ELogLevel::ELogLevel threshold) { this->threshold = threshold; }
 
 
-const CColorMapping & CLogConsoleTarget::getColorMapping() const
-{
-	return colorMapping;
-}
+const CLogFormatter & CLogConsoleTarget::getFormatter() const { return formatter; }
+void CLogConsoleTarget::setFormatter(const CLogFormatter & formatter) { this->formatter = formatter; }
 
 
-void CLogConsoleTarget::setColorMapping(const CColorMapping & colorMapping)
-{
-	this->colorMapping = colorMapping;
-}
+const CColorMapping & CLogConsoleTarget::getColorMapping() const { return colorMapping; }
+void CLogConsoleTarget::setColorMapping(const CColorMapping & colorMapping) { this->colorMapping = colorMapping; }
 
 
-CLogFileTarget::CLogFileTarget(const std::string & filePath, bool append /*= true*/)
-	: file(filePath, append ? std::ios_base::app : std::ios_base::out)
+CLogFileTarget::CLogFileTarget(boost::filesystem::path filePath, bool append /*= true*/)
+	: file(std::move(filePath), append ? std::ios_base::app : std::ios_base::out)
 {
 {
 	formatter.setPattern("%d %l %n [%t] - %m");
 	formatter.setPattern("%d %l %n [%t] - %m");
 }
 }
 
 
-CLogFileTarget::~CLogFileTarget()
-{
-	file.close();
-}
-
 void CLogFileTarget::write(const LogRecord & record)
 void CLogFileTarget::write(const LogRecord & record)
 {
 {
 	TLockGuard _(mx);
 	TLockGuard _(mx);
 	file << formatter.format(record) << std::endl;
 	file << formatter.format(record) << std::endl;
 }
 }
 
 
-const CLogFormatter & CLogFileTarget::getFormatter() const
-{
-	return formatter;
-}
-
-void CLogFileTarget::setFormatter(const CLogFormatter & formatter)
-{
-	this->formatter = formatter;
-}
+const CLogFormatter & CLogFileTarget::getFormatter() const { return formatter; }
+void CLogFileTarget::setFormatter(const CLogFormatter & formatter) { this->formatter = formatter; }

+ 36 - 30
lib/logging/CLogger.h

@@ -19,15 +19,19 @@ class ILogTarget;
 
 
 namespace ELogLevel
 namespace ELogLevel
 {
 {
-enum ELogLevel
-{
-	NOT_SET = 0,
-	TRACE,
-	DEBUG,
-	INFO,
-	WARN,
-	ERROR
-};
+	enum ELogLevel
+	{
+		NOT_SET = 0,
+		TRACE,
+		DEBUG,
+		INFO,
+		WARN,
+		ERROR
+	};
+
+	#ifdef VCMI_ANDROID
+		int toAndroid(ELogLevel logLevel);
+	#endif
 }
 }
 
 
 /// The class CLoggerDomain provides convenient access to super domains from a sub domain.
 /// The class CLoggerDomain provides convenient access to super domains from a sub domain.
@@ -36,9 +40,9 @@ class DLL_LINKAGE CLoggerDomain
 public:
 public:
 	/// Constructs a CLoggerDomain with the domain designated by name.
 	/// Constructs a CLoggerDomain with the domain designated by name.
 	/// Sub-domains can be specified by separating domains by a dot, e.g. "ai.battle". The global domain is named "global".
 	/// Sub-domains can be specified by separating domains by a dot, e.g. "ai.battle". The global domain is named "global".
-	explicit CLoggerDomain(const std::string & name);
+	explicit CLoggerDomain(std::string name);
 
 
-	std::string getName() const;
+	const std::string& getName() const;
 	CLoggerDomain getParent() const;
 	CLoggerDomain getParent() const;
 	bool isGlobalDomain() const;
 	bool isGlobalDomain() const;
 
 
@@ -58,8 +62,11 @@ public:
 	template<typename T>
 	template<typename T>
 	CLoggerStream & operator<<(const T & data)
 	CLoggerStream & operator<<(const T & data)
 	{
 	{
-		if(!sbuffer) sbuffer = new std::stringstream();
+		if(!sbuffer)
+			sbuffer = new std::stringstream(std::ios_base::out);
+
 		(*sbuffer) << data;
 		(*sbuffer) << data;
+
 		return *this;
 		return *this;
 	}
 	}
 
 
@@ -84,18 +91,16 @@ public:
 
 
 	/// Log methods for various log levels
 	/// Log methods for various log levels
 	void trace(const std::string & message) const;
 	void trace(const std::string & message) const;
-	CLoggerStream traceStream() const;
-
 	void debug(const std::string & message) const;
 	void debug(const std::string & message) const;
-	CLoggerStream debugStream() const;
-
 	void info(const std::string & message) const;
 	void info(const std::string & message) const;
-	CLoggerStream infoStream() const;
-
 	void warn(const std::string & message) const;
 	void warn(const std::string & message) const;
-	CLoggerStream warnStream() const;
-
 	void error(const std::string & message) const;
 	void error(const std::string & message) const;
+
+	/// Log streams for various log levels
+	CLoggerStream traceStream() const;
+	CLoggerStream debugStream() const;
+	CLoggerStream infoStream() const;
+	CLoggerStream warnStream() const;
 	CLoggerStream errorStream() const;
 	CLoggerStream errorStream() const;
 
 
 	inline void log(ELogLevel::ELogLevel level, const std::string & message) const;
 	inline void log(ELogLevel::ELogLevel level, const std::string & message) const;
@@ -184,10 +189,7 @@ struct DLL_LINKAGE LogRecord
 {
 {
 	LogRecord(const CLoggerDomain & domain, ELogLevel::ELogLevel level, const std::string & message)
 	LogRecord(const CLoggerDomain & domain, ELogLevel::ELogLevel level, const std::string & message)
 		: domain(domain), level(level), message(message), timeStamp(boost::posix_time::second_clock::local_time()),
 		: domain(domain), level(level), message(message), timeStamp(boost::posix_time::second_clock::local_time()),
-		  threadId(boost::this_thread::get_id())
-	{
-
-	}
+		  threadId(boost::this_thread::get_id()) { }
 
 
 	CLoggerDomain domain;
 	CLoggerDomain domain;
 	ELogLevel::ELogLevel level;
 	ELogLevel::ELogLevel level;
@@ -208,12 +210,17 @@ class DLL_LINKAGE CLogFormatter
 {
 {
 public:
 public:
 	CLogFormatter();
 	CLogFormatter();
-	CLogFormatter(const std::string & pattern);
+	CLogFormatter(const CLogFormatter & copy);
+	CLogFormatter(CLogFormatter && move);
 
 
-	CLogFormatter(const CLogFormatter & other);
-	CLogFormatter & operator=(const CLogFormatter & other);
+	CLogFormatter(const std::string & pattern);
+	
+	CLogFormatter & operator=(const CLogFormatter & copy);
+	CLogFormatter & operator=(CLogFormatter && move);
 
 
 	void setPattern(const std::string & pattern);
 	void setPattern(const std::string & pattern);
+	void setPattern(std::string && pattern);
+
 	const std::string & getPattern() const;
 	const std::string & getPattern() const;
 
 
 	std::string format(const LogRecord & record) const;
 	std::string format(const LogRecord & record) const;
@@ -284,8 +291,7 @@ class DLL_LINKAGE CLogFileTarget : public ILogTarget
 public:
 public:
 	/// Constructs a CLogFileTarget and opens the file designated by filePath. If the append parameter is true, the file
 	/// Constructs a CLogFileTarget and opens the file designated by filePath. If the append parameter is true, the file
 	/// will be appended to. Otherwise the file designated by filePath will be truncated before being opened.
 	/// will be appended to. Otherwise the file designated by filePath will be truncated before being opened.
-	explicit CLogFileTarget(const std::string & filePath, bool append = true);
-	~CLogFileTarget();
+	explicit CLogFileTarget(boost::filesystem::path filePath, bool append = true);
 
 
 	const CLogFormatter & getFormatter() const;
 	const CLogFormatter & getFormatter() const;
 	void setFormatter(const CLogFormatter & formatter);
 	void setFormatter(const CLogFormatter & formatter);
@@ -293,7 +299,7 @@ public:
 	void write(const LogRecord & record) override;
 	void write(const LogRecord & record) override;
 
 
 private:
 private:
-	std::ofstream file;
+	boost::filesystem::ofstream file;
 	CLogFormatter formatter;
 	CLogFormatter formatter;
 	mutable boost::mutex mx;
 	mutable boost::mutex mx;
 };
 };

+ 1 - 1
lib/mapObjects/CArmedInstance.h

@@ -13,7 +13,7 @@
  *
  *
  */
  */
 
 
-class BattleInfo;
+struct BattleInfo;
 class CGameState;
 class CGameState;
 
 
 class DLL_LINKAGE CArmedInstance: public CGObjectInstance, public CBonusSystemNode, public CCreatureSet
 class DLL_LINKAGE CArmedInstance: public CGObjectInstance, public CBonusSystemNode, public CCreatureSet

+ 1 - 1
lib/mapObjects/CBank.h

@@ -13,7 +13,7 @@
  *
  *
  */
  */
 
 
-class BankConfig;
+struct BankConfig;
 class CBankInstanceConstructor;
 class CBankInstanceConstructor;
 
 
 class DLL_LINKAGE CBank : public CArmedInstance
 class DLL_LINKAGE CBank : public CArmedInstance

+ 1 - 1
lib/mapObjects/CGHeroInstance.h

@@ -19,7 +19,7 @@
 class CHero;
 class CHero;
 class CGBoat;
 class CGBoat;
 class CGTownInstance;
 class CGTownInstance;
-class TerrainTile;
+struct TerrainTile;
 
 
 class CGHeroPlaceholder : public CGObjectInstance
 class CGHeroPlaceholder : public CGObjectInstance
 {
 {

+ 1 - 1
lib/mapObjects/CGPandoraBox.h

@@ -14,7 +14,7 @@
  *
  *
  */
  */
 
 
-class InfoWindow;
+struct InfoWindow;
 
 
 class DLL_LINKAGE CGPandoraBox : public CArmedInstance
 class DLL_LINKAGE CGPandoraBox : public CArmedInstance
 {
 {

+ 1 - 1
lib/mapObjects/CObjectHandler.h

@@ -19,7 +19,7 @@
 class CGHeroInstance;
 class CGHeroInstance;
 class IGameCallback;
 class IGameCallback;
 class CGObjectInstance;
 class CGObjectInstance;
-class MetaString;
+struct MetaString;
 struct BattleResult;
 struct BattleResult;
 
 
 class DLL_LINKAGE IObjectInterface
 class DLL_LINKAGE IObjectInterface

+ 87 - 56
lib/rmg/float3.h

@@ -10,75 +10,103 @@
  *
  *
  */
  */
 
 
+// FIXME: Class doesn't contain three float values. Update name and description.
 /// Class which consists of three float values. Represents position virtual RMG (0;1) area.
 /// Class which consists of three float values. Represents position virtual RMG (0;1) area.
 class float3
 class float3
 {
 {
 public:
 public:
 	float x, y;
 	float x, y;
 	si32 z;
 	si32 z;
-	inline float3():x(0),y(0),z(0){}; //c-tor, x/y/z initialized to 0
-	inline float3(const float X, const float Y, const si32 Z):x(X),y(Y),z(Z){}; //c-tor
-	inline float3(const float3 & val) : x(val.x), y(val.y), z(val.z){} //copy c-tor
-	inline float3 & operator=(const float3 & val) {x = val.x; y = val.y; z = val.z; return *this;} //assignemt operator
-	~float3() {} // d-tor - does nothing
-	inline float3 operator+(const float3 & i) const //returns float3 with coordinates increased by corresponding coordinate of given float3
-		{return float3(x+i.x,y+i.y,z+i.z);}
-	inline float3 operator+(const float i) const //returns float3 with coordinates increased by given numer
-		{return float3(x+i,y+i,z+i);}
-	inline float3 operator-(const float3 & i) const //returns float3 with coordinates decreased by corresponding coordinate of given float3
-		{return float3(x-i.x,y-i.y,z-i.z);}
-	inline float3 operator-(const float i) const //returns float3 with coordinates decreased by given numer
-		{return float3(x-i,y-i,z-i);}
-	inline float3 operator*(const float i) const //returns float3 with plane coordinates decreased by given numer
-		{return float3(x*i, y*i, z);}
-	inline float3 operator/(const float i) const //returns float3 with plane coordinates decreased by given numer
-		{return float3(x/i, y/i, z);}
-	inline float3 operator-() const //returns opposite position
-		{return float3(-x,-y,-z);}
-	inline double dist2d(const float3 &other) const //distance (z coord is not used)
-		{return std::sqrt((double)(x-other.x)*(x-other.x) + (y-other.y)*(y-other.y));}
-	inline bool areNeighbours(const float3 &other) const
-		{return dist2d(other) < 2. && z == other.z;}
-	inline void operator+=(const float3 & i)
+
+	float3() : x(0), y(0), z(0) {}
+	float3(const float X, const float Y, const si32 Z): x(X), y(Y), z(Z) {}
+	float3(const float3 & copy) : x(copy.x), y(copy.y), z(copy.z) {}
+	float3 & operator=(const float3 & copy) { x = copy.x; y = copy.y; z = copy.z; return *this; }
+
+	// returns float3 with coordinates increased by corresponding coordinate of given float3
+	float3 operator+(const float3 & i) const { return float3(x + i.x, y + i.y, z + i.z); }
+	// returns float3 with coordinates increased by given numer
+	float3 operator+(const float i) const { return float3(x + i, y + i, z + (si32)i); }
+	// returns float3 with coordinates decreased by corresponding coordinate of given float3
+	float3 operator-(const float3 & i) const { return float3(x - i.x, y - i.y, z - i.z); }
+	// returns float3 with coordinates decreased by given numer
+	float3 operator-(const float i) const { return float3(x - i, y - i, z - (si32)i); }
+	
+	// returns float3 with plane coordinates decreased by given numer
+	float3 operator*(const float i) const {return float3(x * i, y * i, z);}
+	// returns float3 with plane coordinates decreased by given numer
+	float3 operator/(const float i) const {return float3(x / i, y / i, z);}
+	
+	// returns opposite position
+	float3 operator-() const { return float3(-x, -y, -z); }
+	
+	// returns squared distance on Oxy plane (z coord is not used)
+	double dist2dSQ(const float3 & o) const
+	{
+		const double dx = (x - o.x);
+		const double dy = (y - o.y);
+		return dx*dx + dy*dy;
+	}
+	// returns distance on Oxy plane (z coord is not used)
+	double dist2d(const float3 &other) const { return std::sqrt(dist2dSQ(other)); }
+
+	bool areNeighbours(const float3 &other) const { return (dist2dSQ(other) < 4.0) && z == other.z; }
+	
+	float3& operator+=(const float3 & i)
 	{
 	{
-		x+=i.x;
-		y+=i.y;
-		z+=i.z;
+		x += i.x;
+		y += i.y;
+		z += i.z;
+
+		return *this;
 	}
 	}
-	inline void operator+=(const float & i)
+	float3& operator+=(const float & i)
 	{
 	{
-		x+=i;
-		y+=i;
-		z+=i;
+		x += i;
+		y += i;
+		z += (si32)i;
+
+		return *this;
 	}
 	}
-	inline void operator-=(const float3 & i)
+	
+	float3& operator-=(const float3 & i)
 	{
 	{
-		x-=i.x;
-		y-=i.y;
-		z-=i.z;
+		x -= i.x;
+		y -= i.y;
+		z -= i.z;
+
+		return *this;
 	}
 	}
-	inline void operator-=(const float & i)
+	float3& operator-=(const float & i)
 	{
 	{
-		x+=i;
-		y+=i;
-		z+=i;
+		x += i;
+		y += i;
+		z += (si32)i;
+
+		return *this;
 	}
 	}
-	inline void operator*=(const float & i) //scale on plane
+
+	// scale on plane
+	float3& operator*=(const float & i)
 	{
 	{
-		x*=i;
-		y*=i;
+		x *= i;
+		y *= i;
+
+		return *this;
 	}
 	}
-	inline void operator/=(const float & i) //scale on plane
+	// scale on plane
+	float3& operator/=(const float & i)
 	{
 	{
-		x/=i;
-		y/=i;
+		x /= i;
+		y /= i;
+
+		return *this;
 	}
 	}
 
 
-	inline bool operator==(const float3 & i) const
-		{return (x==i.x) && (y==i.y) && (z==i.z);}
-	inline bool operator!=(const float3 & i) const
-		{return !(*this==i);}
-	inline bool operator<(const float3 & i) const
+	bool operator==(const float3 & i) const { return (x == i.x) && (y == i.y) && (z == i.z); }
+	bool operator!=(const float3 & i) const { return (x != i.x) || (y != i.y) || (z != i.z); }
+	
+	bool operator<(const float3 & i) const
 	{
 	{
 		if (z<i.z)
 		if (z<i.z)
 			return true;
 			return true;
@@ -92,32 +120,35 @@ public:
 			return true;
 			return true;
 		if (x>i.x)
 		if (x>i.x)
 			return false;
 			return false;
+
 		return false;
 		return false;
 	}
 	}
-	inline std::string operator ()() const
+
+	std::string operator ()() const
 	{
 	{
 		return	"(" + boost::lexical_cast<std::string>(x) +
 		return	"(" + boost::lexical_cast<std::string>(x) +
 				" " + boost::lexical_cast<std::string>(y) +
 				" " + boost::lexical_cast<std::string>(y) +
 				" " + boost::lexical_cast<std::string>(z) + ")";
 				" " + boost::lexical_cast<std::string>(z) + ")";
 	}
 	}
-	inline bool valid() const
+
+	bool valid() const
 	{
 	{
 		return z >= 0; //minimal condition that needs to be fulfilled for tiles in the map
 		return z >= 0; //minimal condition that needs to be fulfilled for tiles in the map
 	}
 	}
+
 	template <typename Handler> void serialize(Handler &h, const float version)
 	template <typename Handler> void serialize(Handler &h, const float version)
 	{
 	{
 		h & x & y & z;
 		h & x & y & z;
 	}
 	}
-	
 };
 };
+
 inline std::istream & operator>>(std::istream & str, float3 & dest)
 inline std::istream & operator>>(std::istream & str, float3 & dest)
 {
 {
-	str>>dest.x>>dest.y>>dest.z;
-	return str;
+	return str >> dest.x >> dest.y >> dest.z;
 }
 }
 inline std::ostream & operator<<(std::ostream & str, const float3 & sth)
 inline std::ostream & operator<<(std::ostream & str, const float3 & sth)
 {
 {
-	return str<<sth.x<<' '<<sth.y<<' '<<sth.z;
+	return str << sth.x << ' ' << sth.y << ' ' << sth.z;
 }
 }
 
 
 struct Shashfloat3
 struct Shashfloat3

+ 6 - 6
scripting/erm/ERMInterpreter.cpp

@@ -368,19 +368,19 @@ void ERMInterpreter::scanForScripts()
 {
 {
 	using namespace boost::filesystem;
 	using namespace boost::filesystem;
 	//parser checking
 	//parser checking
-	if(!exists(VCMIDirs::get().dataPaths().back() + "/Data/s/"))
+	const path dataPath = VCMIDirs::get().dataPaths().back() / "Data" / "s";
+	if(!exists(dataPath))
 	{
 	{
-		logGlobal->warnStream() << "Warning: Folder " << VCMIDirs::get().dataPaths().back() << "/Data/s/ doesn't exist!";
+		logGlobal->warnStream() << "Warning: Folder " << dataPath << " doesn't exist!";
 		return;
 		return;
 	}
 	}
 	directory_iterator enddir;
 	directory_iterator enddir;
-	for (directory_iterator dir(VCMIDirs::get().dataPaths().back() + "/Data/s"); dir!=enddir; dir++)
+	for (directory_iterator dir(dataPath); dir!=enddir; dir++)
 	{
 	{
 		if(is_regular(dir->status()))
 		if(is_regular(dir->status()))
 		{
 		{
-			std::string name = dir->path().leaf().string();
-			if( boost::algorithm::ends_with(name, ".erm") ||
-				boost::algorithm::ends_with(name, ".verm") )
+			const std::string ext = boost::to_upper_copy(dir->path().extension().string());
+			if (ext == ".ERM" || ext == ".VERM")
 			{
 			{
 				ERMParser ep(dir->path().string());
 				ERMParser ep(dir->path().string());
 				FileInfo * finfo = new FileInfo;
 				FileInfo * finfo = new FileInfo;

+ 8 - 8
server/CVCMIServer.cpp

@@ -18,7 +18,7 @@
 #include "CVCMIServer.h"
 #include "CVCMIServer.h"
 #include "../lib/StartInfo.h"
 #include "../lib/StartInfo.h"
 #include "../lib/mapping/CMap.h"
 #include "../lib/mapping/CMap.h"
-#ifndef __ANDROID__
+#ifndef VCMI_ANDROID
 #include "../lib/Interprocess.h"
 #include "../lib/Interprocess.h"
 #endif
 #endif
 #include "../lib/VCMI_Lib.h"
 #include "../lib/VCMI_Lib.h"
@@ -32,7 +32,7 @@
 
 
 #include "../lib/UnlockGuard.h"
 #include "../lib/UnlockGuard.h"
 
 
-#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(__ANDROID__)
+#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(VCMI_ANDROID)
 #include <execinfo.h>
 #include <execinfo.h>
 #endif
 #endif
 
 
@@ -41,7 +41,7 @@ std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX
 using namespace boost;
 using namespace boost;
 using namespace boost::asio;
 using namespace boost::asio;
 using namespace boost::asio::ip;
 using namespace boost::asio::ip;
-#ifndef __ANDROID__
+#ifndef VCMI_ANDROID
 namespace intpr = boost::interprocess;
 namespace intpr = boost::interprocess;
 #endif
 #endif
 bool end2 = false;
 bool end2 = false;
@@ -393,7 +393,7 @@ void CVCMIServer::newPregame()
 
 
 void CVCMIServer::start()
 void CVCMIServer::start()
 {
 {
-#ifndef __ANDROID__
+#ifndef VCMI_ANDROID
 	ServerReady *sr = nullptr;
 	ServerReady *sr = nullptr;
 	intpr::mapped_region *mr;
 	intpr::mapped_region *mr;
 	try
 	try
@@ -416,7 +416,7 @@ void CVCMIServer::start()
     logNetwork->infoStream()<<"Listening for connections at port " << acceptor->local_endpoint().port();
     logNetwork->infoStream()<<"Listening for connections at port " << acceptor->local_endpoint().port();
 	auto  s = new tcp::socket(acceptor->get_io_service());
 	auto  s = new tcp::socket(acceptor->get_io_service());
 	boost::thread acc(std::bind(vaccept,acceptor,s,&error));
 	boost::thread acc(std::bind(vaccept,acceptor,s,&error));
-#ifndef __ANDROID__
+#ifndef VCMI_ANDROID
 	sr->setToTrueAndNotify();
 	sr->setToTrueAndNotify();
 	delete mr;
 	delete mr;
 #endif
 #endif
@@ -560,7 +560,7 @@ static void handleCommandOptions(int argc, char *argv[])
 	}
 	}
 }
 }
 
 
-#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(__ANDROID__)
+#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(VCMI_ANDROID)
 void handleLinuxSignal(int sig)
 void handleLinuxSignal(int sig)
 {
 {
 	const int STACKTRACE_SIZE = 100;
 	const int STACKTRACE_SIZE = 100;
@@ -591,12 +591,12 @@ int main(int argc, char** argv)
 {
 {
 	// Installs a sig sev segmentation violation handler
 	// Installs a sig sev segmentation violation handler
 	// to log stacktrace
 	// to log stacktrace
-	#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(__ANDROID__)
+	#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(VCMI_ANDROID)
 	signal(SIGSEGV, handleLinuxSignal);
 	signal(SIGSEGV, handleLinuxSignal);
 	#endif
 	#endif
 
 
 	console = new CConsoleHandler;
 	console = new CConsoleHandler;
-	CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Server_log.txt", console);
+	CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() / "VCMI_Server_log.txt", console);
 	logConfig.configureDefault();
 	logConfig.configureDefault();
 
 
 	preinitDLL(console);
 	preinitDLL(console);

+ 1 - 1
test/CVcmiTestConfig.cpp

@@ -22,7 +22,7 @@
 CVcmiTestConfig::CVcmiTestConfig()
 CVcmiTestConfig::CVcmiTestConfig()
 {
 {
 	console = new CConsoleHandler;
 	console = new CConsoleHandler;
-	CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Test_log.txt", console);
+	CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() / "VCMI_Test_log.txt", console);
 	logConfig.configureDefault();
 	logConfig.configureDefault();
 	preinitDLL(console);
 	preinitDLL(console);
 	settings.init();
 	settings.init();