浏览代码

Merge branch 'develop' into feature/VCMIMapFormat1

Conflicts:
	lib/CArtHandler.cpp
AlexVinS 9 年之前
父节点
当前提交
37d0dad70a
共有 100 个文件被更改,包括 893 次插入659 次删除
  1. 3 3
      AI/BattleAI/BattleAI.cpp
  2. 2 2
      AI/BattleAI/BattleAI.h
  3. 2 2
      AI/BattleAI/main.cpp
  4. 1 1
      AI/EmptyAI/CEmptyAI.cpp
  5. 2 2
      AI/EmptyAI/CEmptyAI.h
  6. 2 2
      AI/EmptyAI/exp_funcs.cpp
  7. 2 2
      AI/StupidAI/StupidAI.cpp
  8. 2 2
      AI/StupidAI/StupidAI.h
  9. 2 2
      AI/StupidAI/main.cpp
  10. 0 1
      AI/VCAI/AIUtility.h
  11. 2 3
      AI/VCAI/Fuzzy.cpp
  12. 1 1
      AI/VCAI/Fuzzy.h
  13. 9 10
      AI/VCAI/Goals.cpp
  14. 2 2
      AI/VCAI/Goals.h
  15. 101 121
      AI/VCAI/VCAI.cpp
  16. 5 5
      AI/VCAI/VCAI.h
  17. 2 2
      AI/VCAI/main.cpp
  18. 1 1
      AUTHORS
  19. 4 4
      CCallback.cpp
  20. 4 4
      CCallback.h
  21. 1 1
      CMakeLists.txt
  22. 1 3
      Global.h
  23. 25 12
      client/CMT.cpp
  24. 1 1
      client/CMusicHandler.cpp
  25. 3 3
      client/CMusicHandler.h
  26. 53 12
      client/CPlayerInterface.cpp
  27. 3 3
      client/CPlayerInterface.h
  28. 3 3
      client/CPreGame.cpp
  29. 4 4
      client/CPreGame.h
  30. 43 25
      client/Client.cpp
  31. 15 15
      client/Client.h
  32. 2 2
      client/battle/CBattleInterface.cpp
  33. 6 6
      client/battle/CBattleInterface.h
  34. 1 1
      client/battle/CCreatureAnimation.h
  35. 1 1
      client/mapHandler.cpp
  36. 10 1
      client/widgets/MiscWidgets.cpp
  37. 29 18
      client/windows/CAdvmapInterface.cpp
  38. 1 0
      client/windows/CAdvmapInterface.h
  39. 5 2
      client/windows/CCastleInterface.cpp
  40. 2 2
      client/windows/CQuestLog.cpp
  41. 2 2
      client/windows/CQuestLog.h
  42. 1 1
      client/windows/CTradeWindow.cpp
  43. 2 2
      client/windows/GUIClasses.cpp
  44. 1 1
      lib/BattleAction.cpp
  45. 13 15
      lib/BattleState.cpp
  46. 2 2
      lib/BattleState.h
  47. 5 4
      lib/CArtHandler.cpp
  48. 2 2
      lib/CArtHandler.h
  49. 5 5
      lib/CBattleCallback.cpp
  50. 2 2
      lib/CBattleCallback.h
  51. 1 1
      lib/CConfigHandler.h
  52. 10 3
      lib/CCreatureHandler.cpp
  53. 28 3
      lib/CCreatureSet.cpp
  54. 2 1
      lib/CCreatureSet.h
  55. 3 3
      lib/CGameInfoCallback.cpp
  56. 1 1
      lib/CGameInfoCallback.h
  57. 10 10
      lib/CGameInterface.cpp
  58. 7 7
      lib/CGameInterface.h
  59. 4 4
      lib/CGameState.cpp
  60. 3 3
      lib/CGameState.h
  61. 70 18
      lib/CPathfinder.cpp
  62. 7 3
      lib/CPathfinder.h
  63. 1 1
      lib/CStopWatch.h
  64. 37 40
      lib/Connection.cpp
  65. 118 110
      lib/Connection.h
  66. 3 2
      lib/GameConstants.h
  67. 13 18
      lib/HeroBonus.cpp
  68. 3 4
      lib/HeroBonus.h
  69. 3 3
      lib/JsonNode.cpp
  70. 2 5
      lib/NetPacks.h
  71. 8 6
      lib/NetPacksLib.cpp
  72. 2 2
      lib/StartInfo.h
  73. 1 1
      lib/StringConstants.h
  74. 9 0
      lib/VCMI_lib.vcxproj
  75. 36 3
      lib/VCMI_lib.vcxproj.filters
  76. 1 1
      lib/filesystem/CCompressedStream.h
  77. 1 1
      lib/logging/CLogger.cpp
  78. 3 3
      lib/logging/CLogger.h
  79. 3 2
      lib/mapObjects/CArmedInstance.cpp
  80. 2 2
      lib/mapObjects/CBank.cpp
  81. 4 2
      lib/mapObjects/CGHeroInstance.cpp
  82. 1 1
      lib/mapObjects/CGHeroInstance.h
  83. 7 7
      lib/mapObjects/CGPandoraBox.cpp
  84. 4 1
      lib/mapObjects/CGTownInstance.cpp
  85. 1 1
      lib/mapObjects/CObjectHandler.cpp
  86. 3 3
      lib/mapObjects/CommonConstructors.cpp
  87. 3 2
      lib/mapObjects/CommonConstructors.h
  88. 1 1
      lib/mapObjects/JsonRandom.cpp
  89. 59 32
      lib/mapObjects/MiscObjects.cpp
  90. 1 1
      lib/mapObjects/MiscObjects.h
  91. 2 2
      lib/mapping/CCampaignHandler.cpp
  92. 3 3
      lib/mapping/CCampaignHandler.h
  93. 1 1
      lib/mapping/CMap.cpp
  94. 2 2
      lib/mapping/CMap.h
  95. 2 2
      lib/mapping/CMapDefines.h
  96. 3 3
      lib/mapping/CMapEditManager.cpp
  97. 5 5
      lib/mapping/CMapEditManager.h
  98. 4 4
      lib/mapping/CMapInfo.h
  99. 1 1
      lib/rmg/CMapGenerator.h
  100. 1 1
      lib/rmg/CZoneGraphGenerator.cpp

+ 3 - 3
AI/BattleAI/BattleAI.cpp

@@ -8,7 +8,7 @@
 #include "../../lib/VCMI_Lib.h"
 
 using boost::optional;
-static shared_ptr<CBattleCallback> cbc;
+static std::shared_ptr<CBattleCallback> cbc;
 
 #define LOGL(text) print(text)
 #define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl))
@@ -91,7 +91,7 @@ CBattleAI::~CBattleAI(void)
 	}
 }
 
-void CBattleAI::init(shared_ptr<CBattleCallback> CB)
+void CBattleAI::init(std::shared_ptr<CBattleCallback> CB)
 {
 	print("init called, saving ptr to IBattleCallback");
 	cbc = cb = CB;
@@ -610,7 +610,7 @@ ThreatMap::ThreatMap(const CStack *Endangered) : endangered(Endangered)
 
 const TBonusListPtr StackWithBonuses::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= nullptr*/, const std::string &cachingStr /*= ""*/) const
 {
-	TBonusListPtr ret = make_shared<BonusList>();
+	TBonusListPtr ret = std::make_shared<BonusList>();
 	const TBonusListPtr originalList = stack->getAllBonuses(selector, limit, root, cachingStr);
 	range::copy(*originalList, std::back_inserter(*ret));
 	for(auto &bonus : bonusesToAdd)

+ 2 - 2
AI/BattleAI/BattleAI.h

@@ -110,7 +110,7 @@ struct PotentialTargets
 class CBattleAI : public CBattleGameInterface
 {
 	int side;
-	shared_ptr<CBattleCallback> cb;
+	std::shared_ptr<CBattleCallback> cb;
 	
 	//Previous setting of cb 
 	bool wasWaitingForRealize, wasUnlockingGs;
@@ -120,7 +120,7 @@ public:
 	CBattleAI(void);
 	~CBattleAI(void);
 
-	void init(shared_ptr<CBattleCallback> CB) override;
+	void init(std::shared_ptr<CBattleCallback> CB) override;
 	void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
 	void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
 	BattleAction activeStack(const CStack * stack) override; //called when it's turn of that stack

+ 2 - 2
AI/BattleAI/main.cpp

@@ -25,7 +25,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
 	strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
 }
 
-extern "C" DLL_EXPORT void GetNewBattleAI(shared_ptr<CBattleGameInterface> &out)
+extern "C" DLL_EXPORT void GetNewBattleAI(std::shared_ptr<CBattleGameInterface> &out)
 {
-	out = make_shared<CBattleAI>();
+	out = std::make_shared<CBattleAI>();
 }

+ 1 - 1
AI/EmptyAI/CEmptyAI.cpp

@@ -3,7 +3,7 @@
 
 #include "../../lib/CRandomGenerator.h"
 
-void CEmptyAI::init(shared_ptr<CCallback> CB)
+void CEmptyAI::init(std::shared_ptr<CCallback> CB)
 {
 	cb = CB;
 	human=false;

+ 2 - 2
AI/EmptyAI/CEmptyAI.h

@@ -7,10 +7,10 @@ struct HeroMoveDetails;
 
 class CEmptyAI : public CGlobalAI
 {
-	shared_ptr<CCallback> cb;
+	std::shared_ptr<CCallback> cb;
 
 public:
-	void init(shared_ptr<CCallback> CB) override;
+	void init(std::shared_ptr<CCallback> CB) override;
 	void yourTurn() override;
 	void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) override;
 	void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID) override;

+ 2 - 2
AI/EmptyAI/exp_funcs.cpp

@@ -13,7 +13,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
 	strcpy(name,NAME);
 }
 
-extern "C" DLL_EXPORT void GetNewAI(shared_ptr<CGlobalAI> &out)
+extern "C" DLL_EXPORT void GetNewAI(std::shared_ptr<CGlobalAI> &out)
 {
-	out = make_shared<CEmptyAI>();
+	out = std::make_shared<CEmptyAI>();
 }

+ 2 - 2
AI/StupidAI/StupidAI.cpp

@@ -5,7 +5,7 @@
 #include "../../CCallback.h"
 #include "../../lib/CCreatureHandler.h"
 
-static shared_ptr<CBattleCallback> cbc;
+static std::shared_ptr<CBattleCallback> cbc;
 
 CStupidAI::CStupidAI(void)
 	: side(-1)
@@ -19,7 +19,7 @@ CStupidAI::~CStupidAI(void)
 	print("destroyed");
 }
 
-void CStupidAI::init(shared_ptr<CBattleCallback> CB)
+void CStupidAI::init(std::shared_ptr<CBattleCallback> CB)
 {
 	print("init called, saving ptr to IBattleCallback");
 	cbc = cb = CB;

+ 2 - 2
AI/StupidAI/StupidAI.h

@@ -5,14 +5,14 @@
 class CStupidAI : public CBattleGameInterface
 {
 	int side;
-	shared_ptr<CBattleCallback> cb;
+	std::shared_ptr<CBattleCallback> cb;
 
 	void print(const std::string &text) const;
 public:
 	CStupidAI(void);
 	~CStupidAI(void);
 
-	void init(shared_ptr<CBattleCallback> CB) override;
+	void init(std::shared_ptr<CBattleCallback> CB) override;
 	void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
 	void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
 	BattleAction activeStack(const CStack * stack) override; //called when it's turn of that stack

+ 2 - 2
AI/StupidAI/main.cpp

@@ -25,7 +25,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
 	strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
 }
 
-extern "C" DLL_EXPORT void GetNewBattleAI(shared_ptr<CBattleGameInterface> &out)
+extern "C" DLL_EXPORT void GetNewBattleAI(std::shared_ptr<CBattleGameInterface> &out)
 {
-	out = make_shared<CStupidAI>();
+	out = std::make_shared<CStupidAI>();
 }

+ 0 - 1
AI/VCAI/AIUtility.h

@@ -23,7 +23,6 @@ class CCallback;
 typedef const int3& crint3;
 typedef const std::string& crstring;
 
-const int HERO_GOLD_COST = 2500;
 const int GOLD_MINE_PRODUCTION = 1000, WOOD_ORE_MINE_PRODUCTION = 2, RESOURCE_MINE_PRODUCTION = 1;
 const int ACTUAL_RESOURCE_COUNT = 7;
 const int ALLOWED_ROAMING_HEROES = 8;

+ 2 - 3
AI/VCAI/Fuzzy.cpp

@@ -31,7 +31,6 @@ class Engine;
 class InputVariable;
 class CGTownInstance;
 
-using namespace vstd;
 //using namespace Goals;
 
 FuzzyHelper *fh;
@@ -85,7 +84,7 @@ armyStructure evaluateArmyStructure (const CArmedInstance * army)
 		if (walker)
 			walkersStrenght += s.second->getPower();
 
-		amax (maxSpeed, s.second->type->valOfBonuses(Bonus::STACKS_SPEED));
+		vstd::amax(maxSpeed, s.second->type->valOfBonuses(Bonus::STACKS_SPEED));
 	}
 	armyStructure as;
 	as.walkers = walkersStrenght / totalStrenght;
@@ -297,7 +296,7 @@ FuzzyHelper::TacticalAdvantage::~TacticalAdvantage()
 	delete threat;
 }
 
-//shared_ptr<AbstractGoal> chooseSolution (std::vector<shared_ptr<AbstractGoal>> & vec)
+//std::shared_ptr<AbstractGoal> chooseSolution (std::vector<std::shared_ptr<AbstractGoal>> & vec)
 
 Goals::TSubgoal FuzzyHelper::chooseSolution (Goals::TGoalVec vec)
 {

+ 1 - 1
AI/VCAI/Fuzzy.h

@@ -83,5 +83,5 @@ public:
 	float getTacticalAdvantage (const CArmedInstance *we, const CArmedInstance *enemy); //returns factor how many times enemy is stronger than us
 
 	Goals::TSubgoal chooseSolution (Goals::TGoalVec vec);
-	//shared_ptr<AbstractGoal> chooseSolution (std::vector<shared_ptr<AbstractGoal>> & vec);
+	//std::shared_ptr<AbstractGoal> chooseSolution (std::vector<std::shared_ptr<AbstractGoal>> & vec);
 };

+ 9 - 10
AI/VCAI/Goals.cpp

@@ -19,12 +19,11 @@ extern boost::thread_specific_ptr<CCallback> cb;
 extern boost::thread_specific_ptr<VCAI> ai;
 extern FuzzyHelper * fh; //TODO: this logic should be moved inside VCAI
 
-using namespace vstd;
 using namespace Goals;
 
 TSubgoal Goals::sptr(const AbstractGoal & tmp)
 {
-	shared_ptr<AbstractGoal> ptr;
+	std::shared_ptr<AbstractGoal> ptr;
 	ptr.reset(tmp.clone());
 	return ptr;
 }
@@ -575,7 +574,7 @@ TGoalVec Explore::getAllPossibleSubgoals()
 	{
 		//heroes = ai->getUnblockedHeroes();
 		heroes = cb->getHeroesInfo();
-		erase_if (heroes, [](const HeroPtr h)
+		vstd::erase_if(heroes, [](const HeroPtr h)
 		{
 			if (ai->getGoal(h)->goalType == Goals::EXPLORE) //do not reassign hero who is already explorer
 				return true;
@@ -693,8 +692,8 @@ TSubgoal RecruitHero::whatToDoToAchieve()
 	if(!t)
 		return sptr (Goals::BuildThis(BuildingID::TAVERN));
 
-	if(cb->getResourceAmount(Res::GOLD) < HERO_GOLD_COST)
-		return sptr (Goals::CollectRes(Res::GOLD, HERO_GOLD_COST));
+	if(cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST)
+		return sptr (Goals::CollectRes(Res::GOLD, GameConstants::HERO_GOLD_COST));
 
 	return iAmElementar();
 }
@@ -747,10 +746,10 @@ TGoalVec VisitTile::getAllPossibleSubgoals()
 		if (ai->canRecruitAnyHero())
 			ret.push_back (sptr(Goals::RecruitHero()));
 	}
-	if (ret.empty())
+	if(ret.empty())
 	{
-		auto obj = frontOrNull(cb->getVisitableObjs(tile));
-		if (obj && obj->ID == Obj::HERO && obj->tempOwner == ai->playerID) //our own hero stands on that tile
+		auto obj = vstd::frontOrNull(cb->getVisitableObjs(tile));
+		if(obj && obj->ID == Obj::HERO && obj->tempOwner == ai->playerID) //our own hero stands on that tile
 		{
 			if (hero.get(true) && hero->id == obj->id) //if it's assigned hero, visit tile. If it's different hero, we can't visit tile now
 				ret.push_back(sptr(Goals::VisitTile(tile).sethero(dynamic_cast<const CGHeroInstance *>(obj)).setisElementar(true)));
@@ -767,7 +766,7 @@ TGoalVec VisitTile::getAllPossibleSubgoals()
 
 TSubgoal DigAtTile::whatToDoToAchieve()
 {
-	const CGObjectInstance *firstObj = frontOrNull(cb->getVisitableObjs(tile));
+	const CGObjectInstance *firstObj = vstd::frontOrNull(cb->getVisitableObjs(tile));
 	if(firstObj && firstObj->ID == Obj::HERO && firstObj->tempOwner == ai->playerID) //we have hero at dest
 	{
 		const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(firstObj);
@@ -1057,7 +1056,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
 
 	auto otherHeroes = cb->getHeroesInfo();
 	auto heroDummy = hero;
-	erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
+	vstd::erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
 	{
 		return (h == heroDummy.h || !ai->isAccessibleForHero(heroDummy->visitablePos(), h, true)
 			|| !ai->canGetArmy(heroDummy.h, h) || ai->getGoal(h)->goalType == Goals::GATHER_ARMY);

+ 2 - 2
AI/VCAI/Goals.h

@@ -107,7 +107,7 @@ public:
 	static TSubgoal tryRecruitHero();
 
 	///Visitor pattern
-	//TODO: make accept work for shared_ptr... somehow
+	//TODO: make accept work for std::shared_ptr... somehow
 	virtual void accept (VCAI * ai); //unhandled goal will report standard error
 	virtual float accept (FuzzyHelper * f);
 
@@ -162,7 +162,7 @@ public:
 	TSubgoal iAmElementar()
 	{
 		setisElementar(true);
-		shared_ptr<AbstractGoal> ptr;
+		std::shared_ptr<AbstractGoal> ptr;
 		ptr.reset(clone());
 		return ptr;
 	}

+ 101 - 121
AI/VCAI/VCAI.cpp

@@ -13,7 +13,7 @@
 
 
 /*
- * CCreatureHandler.h, part of VCMI engine
+ * VCAI.cpp, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -29,8 +29,6 @@ class CGVisitableOPW;
 const double SAFE_ATTACK_CONSTANT = 1.5;
 const int GOLD_RESERVE = 10000; //when buying creatures we want to keep at least this much gold (10000 so at least we'll be able to reach capitol)
 
-using namespace vstd;
-
 //one thread may be turn of AI and another will be handling a side effect for AI2
 boost::thread_specific_ptr<CCallback> cb;
 boost::thread_specific_ptr<VCAI> ai;
@@ -124,8 +122,8 @@ void VCAI::heroMoved(const TryMoveHero & details)
 	{
 		const int3 from = CGHeroInstance::convertPosition(details.start, false),
 			to = CGHeroInstance::convertPosition(details.end, false);
-		const CGObjectInstance *o1 = frontOrNull(cb->getVisitableObjs(from)),
-			*o2 = frontOrNull(cb->getVisitableObjs(to));
+		const CGObjectInstance *o1 = vstd::frontOrNull(cb->getVisitableObjs(from)),
+			*o2 = vstd::frontOrNull(cb->getVisitableObjs(to));
 
 		auto t1 = dynamic_cast<const CGTeleport *>(o1);
 		auto t2 = dynamic_cast<const CGTeleport *>(o2);
@@ -394,8 +392,8 @@ void VCAI::objectRemoved(const CGObjectInstance *obj)
 	LOG_TRACE(logAi);
 	NET_EVENT_HANDLER;
 
-	erase_if_present(visitableObjs, obj);
-	erase_if_present(alreadyVisited, obj);
+	vstd::erase_if_present(visitableObjs, obj);
+	vstd::erase_if_present(alreadyVisited, obj);
 
 	for (auto h : cb->getHeroesInfo())
 		unreserveObject(h, obj);
@@ -518,15 +516,15 @@ void VCAI::objectPropertyChanged(const SetObjectProperty * sop)
 	{
 		//we don't want to visit know object twice (do we really?)
 		if(sop->val == playerID.getNum())
-			erase_if_present(visitableObjs, myCb->getObj(sop->id));
-		else if (myCb->getPlayerRelations(playerID, (PlayerColor)sop->val) == PlayerRelations::ENEMIES)
+			vstd::erase_if_present(visitableObjs, myCb->getObj(sop->id));
+		else if(myCb->getPlayerRelations(playerID, (PlayerColor)sop->val) == PlayerRelations::ENEMIES)
 		{
 			//we want to visit objects owned by oppponents
 			auto obj = myCb->getObj(sop->id, false);
 			if (obj)
 			{
 				addVisitableObj(obj);
-				erase_if_present(alreadyVisited, obj);
+				vstd::erase_if_present(alreadyVisited, obj);
 			}
 		}
 	}
@@ -557,7 +555,7 @@ void VCAI::showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions)
 	NET_EVENT_HANDLER;
 }
 
-void VCAI::init(shared_ptr<CCallback> CB)
+void VCAI::init(std::shared_ptr<CCallback> CB)
 {
 	LOG_TRACE(logAi);
 	myCb = CB;
@@ -738,7 +736,7 @@ void VCAI::makeTurn()
 				if (isWeeklyRevisitable(obj))
 				{
 					addVisitableObj(obj);
-					erase_if_present (alreadyVisited, obj);
+					vstd::erase_if_present(alreadyVisited, obj);
 				}
 			}
 		}
@@ -841,7 +839,7 @@ void VCAI::makeTurnInternal()
 		{
 			if (h->movement)
 				logAi->warnStream() << boost::format("hero %s has %d MP left") % h->name % h->movement;
-		}	
+		}
 	}
 	catch(boost::thread_interrupted &e)
 	{
@@ -910,7 +908,7 @@ bool VCAI::canGetArmy (const CGHeroInstance * army, const CGHeroInstance * sourc
 
 
 	const CArmedInstance *armies[] = {army, source};
- 
+
 	//we calculate total strength for each creature type available in armies
 	std::map<const CCreature*, int> creToPower;
 	for(auto armyPtr : armies)
@@ -945,7 +943,7 @@ bool VCAI::canGetArmy (const CGHeroInstance * army, const CGHeroInstance * sourc
 				if(armyPtr->getCreature(SlotID(j)) == bestArmy[i]  &&  armyPtr != army) //it's a searched creature not in dst ARMY
 				{
 					//FIXME: line below is useless when simulating exchange between two non-singular armies
-					if (!(armyPtr->needsLastStack() && armyPtr->Slots().size() == 1)) //can't take away last creature
+					if(!(armyPtr->needsLastStack() && armyPtr->stacksCount() == 1)) //can't take away last creature
 						return true; //at least one exchange will be performed
 					else
 						return false; //no further exchange possible
@@ -992,7 +990,7 @@ void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance *
 			for (int j = 0; j < GameConstants::ARMY_SIZE; j++)
 			{
 				if(armyPtr->getCreature(SlotID(j)) == bestArmy[i]  &&  (i != j || armyPtr != army)) //it's a searched creature not in dst SLOT
-					if (!(armyPtr->needsLastStack() && armyPtr->Slots().size() == 1)) //can't take away last creature
+					if(!(armyPtr->needsLastStack() && armyPtr->stacksCount() == 1)) //can't take away last creature
 						cb->mergeOrSwapStacks(armyPtr, army, SlotID(j), SlotID(i));
 			}
 	}
@@ -1007,7 +1005,7 @@ void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance *
 }
 
 void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * other)
-{	
+{
 	auto equipBest = [](const CGHeroInstance * h, const CGHeroInstance * otherh, bool giveStuffToFirstHero) -> void
 	{
 		bool changeMade = false;
@@ -1052,6 +1050,9 @@ void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * ot
 				if (location.relatedObj() == target && location.slot < ArtifactPosition::AFTER_LAST)
 					continue; //don't reequip artifact we already wear
 
+				if(location.slot == ArtifactPosition::MACH4) // don't attempt to move catapult
+					continue;
+
 				auto s = location.getSlot();
 				if (!s || s->locked) //we can't move locks
 					continue;
@@ -1118,7 +1119,7 @@ void VCAI::recruitCreatures(const CGDwelling * d, const CArmedInstance * recruit
 // 		if(containsSavedRes(c->cost))
 // 			continue;
 
-		amin(count, freeResources() / VLC->creh->creatures[creID]->cost);
+		vstd::amin(count, freeResources() / VLC->creh->creatures[creID]->cost);
 		if(count > 0)
 			cb->recruitCreatures(d, recruiter, creID, count, i);
 	}
@@ -1445,7 +1446,7 @@ bool VCAI::canRecruitAnyHero (const CGTownInstance * t) const
 	if (!t)
 		t = findTownWithTavern();
 	if (t)
-		return cb->getResourceAmount(Res::GOLD) >= HERO_GOLD_COST &&
+		return cb->getResourceAmount(Res::GOLD) >= GameConstants::HERO_GOLD_COST &&
 			cb->getHeroesInfo().size() < ALLOWED_ROAMING_HEROES &&
 			cb->getAvailableHeroes(t).size();
 	else
@@ -1481,7 +1482,7 @@ void VCAI::wander(HeroPtr h)
 		}
 
 		range::copy(getPossibleDestinations(h), std::back_inserter(dests));
-		erase_if(dests, [&](ObjectIdRef obj) -> bool
+		vstd::erase_if(dests, [&](ObjectIdRef obj) -> bool
 		{
 			return !isSafeToVisit(h, sm->firstTileToGet(h, obj->visitablePos()));
 		});
@@ -1530,10 +1531,10 @@ void VCAI::wander(HeroPtr h)
 				}
 				break;
 			}
-			else if(cb->getResourceAmount(Res::GOLD) >= HERO_GOLD_COST)
+			else if(cb->getResourceAmount(Res::GOLD) >= GameConstants::HERO_GOLD_COST)
 			{
 				std::vector<const CGTownInstance *> towns = cb->getTownsInfo();
-				erase_if(towns, [](const CGTownInstance *t) -> bool
+				vstd::erase_if(towns, [](const CGTownInstance *t) -> bool
 				{
 					for(const CGHeroInstance *h : cb->getHeroesInfo())
 					if(!t->getArmyStrength() || howManyReinforcementsCanGet(h, t))
@@ -1584,8 +1585,8 @@ void VCAI::wander(HeroPtr h)
 
 void VCAI::setGoal(HeroPtr h, Goals::TSubgoal goal)
 { //TODO: check for presence?
-	if (goal->invalid())
-		erase_if_present(lockedHeroes, h);
+	if(goal->invalid())
+		vstd::erase_if_present(lockedHeroes, h);
 	else
 	{
 		lockedHeroes[h] = goal;
@@ -1626,7 +1627,7 @@ void VCAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int
 	NET_EVENT_HANDLER;
 	assert(playerID > PlayerColor::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
 	status.setBattle(ONGOING_BATTLE);
-	const CGObjectInstance *presumedEnemy = backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
+	const CGObjectInstance *presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
 	battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile);
 	CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side);
 }
@@ -1666,8 +1667,8 @@ void VCAI::reserveObject(HeroPtr h, const CGObjectInstance *obj)
 
 void VCAI::unreserveObject(HeroPtr h, const CGObjectInstance *obj)
 {
-	erase_if_present(reservedObjs, obj); //unreserve objects
-	erase_if_present(reservedHeroesMap[h], obj);
+	vstd::erase_if_present(reservedObjs, obj); //unreserve objects
+	vstd::erase_if_present(reservedHeroesMap[h], obj);
 }
 
 void VCAI::markHeroUnableToExplore (HeroPtr h)
@@ -1676,7 +1677,7 @@ void VCAI::markHeroUnableToExplore (HeroPtr h)
 }
 void VCAI::markHeroAbleToExplore (HeroPtr h)
 {
-	erase_if_present(heroesUnableToExplore, h);
+	vstd::erase_if_present(heroesUnableToExplore, h);
 }
 bool VCAI::isAbleToExplore (HeroPtr h)
 {
@@ -1697,7 +1698,7 @@ void VCAI::validateVisitableObjs()
 	auto shouldBeErased = [&](const CGObjectInstance *obj) -> bool
 	{
 		if (obj)
-			return !cb->getObj(obj->id);
+			return !cb->getObj(obj->id, false); // no verbose output needed as we check object visibility
 		else
 			return true;
 
@@ -1713,25 +1714,25 @@ void VCAI::validateVisitableObjs()
 
 	//errorMsg is captured by ref so lambda will take the new text
 	errorMsg = " shouldn't be on the visitable objects list!";
-	erase_if(visitableObjs, shouldBeErased);
+	vstd::erase_if(visitableObjs, shouldBeErased);
 
 	//FIXME: how comes our own heroes become inaccessible?
-	erase_if(reservedHeroesMap, [](std::pair<HeroPtr, std::set<const CGObjectInstance *>> hp) -> bool
+	vstd::erase_if(reservedHeroesMap, [](std::pair<HeroPtr, std::set<const CGObjectInstance *>> hp) -> bool
 	{
 		return !hp.first.get(true);
 	});
 	for(auto &p : reservedHeroesMap)
 	{
 		errorMsg = " shouldn't be on list for hero " + p.first->name + "!";
-		erase_if(p.second, shouldBeErased);
+		vstd::erase_if(p.second, shouldBeErased);
 	}
 
 	errorMsg = " shouldn't be on the reserved objs list!";
-	erase_if(reservedObjs, shouldBeErased);
+	vstd::erase_if(reservedObjs, shouldBeErased);
 
 	//TODO overkill, hidden object should not be removed. However, we can't know if hidden object is erased from game.
 	errorMsg = " shouldn't be on the already visited objs list!";
-	erase_if(alreadyVisited, shouldBeErased);
+	vstd::erase_if(alreadyVisited, shouldBeErased);
 }
 
 void VCAI::retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned /*= false*/) const
@@ -1762,7 +1763,7 @@ std::vector<const CGObjectInstance *> VCAI::getFlaggedObjects() const
 {
 	std::vector<const CGObjectInstance *> ret;
 	retreiveVisitableObjs(ret, true);
-	erase_if(ret, [](const CGObjectInstance *obj)
+	vstd::erase_if(ret, [](const CGObjectInstance *obj)
 	{
 		return obj->tempOwner != ai->playerID;
 	});
@@ -1784,7 +1785,7 @@ const CGObjectInstance * VCAI::lookForArt(int aid) const
 {
 	for(const CGObjectInstance *obj : ai->visitableObjs)
 	{
-		if(obj->ID == 5 && obj->subID == aid)
+		if(obj->ID == Obj::ARTIFACT && obj->subID == aid)
 			return obj;
 	}
 
@@ -1876,6 +1877,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
             logAi->errorStream() << "Hero " << h->name << " cannot reach " << dst;
 			throw goalFulfilledException (sptr(Goals::VisitTile(dst).sethero(h)));
 		}
+		int i = path.nodes.size()-1;
 
 		auto getObj = [&](int3 coord, bool ignoreHero)
 		{
@@ -1885,6 +1887,31 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
 			//return cb->getTile(coord,false)->topVisitableObj(ignoreHero);
 		};
 
+		auto isTeleportAction = [&](CGPathNode::ENodeAction action) -> bool
+		{
+			if(action != CGPathNode::TELEPORT_NORMAL &&
+				action != CGPathNode::TELEPORT_BLOCKING_VISIT &&
+				action != CGPathNode::TELEPORT_BATTLE)
+			{
+				return false;
+			}
+
+			return true;
+		};
+
+		auto getDestTeleportObj = [&](const CGObjectInstance * currentObject, const CGObjectInstance * nextObjectTop, const CGObjectInstance * nextObject) -> const CGObjectInstance *
+		{
+			if(CGTeleport::isConnected(currentObject, nextObjectTop))
+				return nextObjectTop;
+			if(nextObjectTop && nextObjectTop->ID == Obj::HERO &&
+				CGTeleport::isConnected(currentObject, nextObject))
+			{
+				return nextObject;
+			}
+
+			return nullptr;
+		};
+
 		auto doMovement = [&](int3 dst, bool transit)
 		{
 			cb->moveHero(*h, CGHeroInstance::convertPosition(dst, true), transit);
@@ -1915,17 +1942,18 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
 			doTeleportMovement(currentExit, currentPos);
 		};
 
-		int i=path.nodes.size()-1;
 		for(; i>0; i--)
 		{
 			int3 currentCoord = path.nodes[i].coord;
 			int3 nextCoord = path.nodes[i-1].coord;
 
 			auto currentObject = getObj(currentCoord, currentCoord == CGHeroInstance::convertPosition(h->pos,false));
-			auto nextObject = getObj(nextCoord, false);
-			if(CGTeleport::isConnected(currentObject, nextObject))
+			auto nextObjectTop = getObj(nextCoord, false);
+			auto nextObject = getObj(nextCoord, true);
+			auto destTeleportObj = getDestTeleportObj(currentObject, nextObjectTop, nextObject);
+			if(isTeleportAction(path.nodes[i-1].action) && destTeleportObj != nullptr)
 			{ //we use special login if hero standing on teleporter it's mean we need
-				doTeleportMovement(nextObject->id, nextCoord);
+				doTeleportMovement(destTeleportObj->id, nextCoord);
 				if(teleportChannelProbingList.size())
 					doChannelProbing();
 
@@ -1944,8 +1972,8 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
 				continue;
 
 			if((i-2 >= 0) // Check there is node after next one; otherwise transit is pointless
-				&& (CGTeleport::isConnected(nextObject, getObj(path.nodes[i-2].coord, false))
-					|| CGTeleport::isTeleport(nextObject)))
+				&& (CGTeleport::isConnected(nextObjectTop, getObj(path.nodes[i-2].coord, false))
+					|| CGTeleport::isTeleport(nextObjectTop)))
 			{ // Hero should be able to go through object if it's allow transit
 				doMovement(endpos, true);
 			}
@@ -1963,7 +1991,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
 	}
 	if (h)
 	{
-		if (auto visitedObject = frontOrNull(cb->getVisitableObjs(h->visitablePos()))) //we stand on something interesting
+		if(auto visitedObject = vstd::frontOrNull(cb->getVisitableObjs(h->visitablePos()))) //we stand on something interesting
 		{
 			if (visitedObject != *h)
 				performObjectInteraction (visitedObject, h);
@@ -1974,16 +2002,16 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
 		completeGoal (sptr(Goals::VisitTile(dst).sethero(h))); //we stepped on some tile, anyway
 		completeGoal (sptr(Goals::ClearWayTo(dst).sethero(h)));
 
-		if (!ret) //reserve object we are heading towards
+		if(!ret) //reserve object we are heading towards
 		{
-			auto obj = frontOrNull(cb->getVisitableObjs(dst));
-			if (obj && obj != *h)
+			auto obj = vstd::frontOrNull(cb->getVisitableObjs(dst));
+			if(obj && obj != *h)
 				reserveObject(h, obj);
 		}
 
-		if (startHpos == h->visitablePos() && !ret) //we didn't move and didn't reach the target
+		if(startHpos == h->visitablePos() && !ret) //we didn't move and didn't reach the target
 		{
-			erase_if_present (lockedHeroes, h); //hero seemingly is confused
+			vstd::erase_if_present(lockedHeroes, h); //hero seemingly is confused
 			throw cannotFulfillGoalException("Invalid path found!"); //FIXME: should never happen
 		}
 		logAi->debugStream() << boost::format("Hero %s moved from %s to %s. Returning %d.") % h->name % startHpos % h->visitablePos() % ret;
@@ -2101,7 +2129,7 @@ void VCAI::tryRealize(Goals::CollectRes & g)
 				cb->trade(obj, EMarketMode::RESOURCE_RESOURCE, i, g.resID, toGive);
 				if(cb->getResourceAmount(static_cast<Res::ERes>(g.resID)) >= g.value)
 					return;
-			} 
+			}
 
 			throw cannotFulfillGoalException("I cannot get needed resources by trade!");
 		}
@@ -2290,7 +2318,7 @@ Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool on
 				}
 				else
 				{
-					erase_if_present (lockedHeroes, goal->hero); // we seemingly don't know what to do with hero
+					vstd::erase_if_present (lockedHeroes, goal->hero); // we seemingly don't know what to do with hero
 				}
 			}
 
@@ -2319,7 +2347,7 @@ Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool on
 			completeGoal (goal);
 			//completed goal was main goal //TODO: find better condition
 			if (ultimateGoal->fulfillsMe(goal) || maxGoals > searchDepth2)
-				return sptr(Goals::Invalid()); 
+				return sptr(Goals::Invalid());
 		}
 		catch(std::exception &e)
 		{
@@ -2545,7 +2573,7 @@ int3 VCAI::explorationNewPoint(HeroPtr h)
 	for (int i = 1; i < radius; i++)
 	{
 		getVisibleNeighbours(tiles[i-1], tiles[i]);
-		removeDuplicates(tiles[i]);
+		vstd::removeDuplicates(tiles[i]);
 
 		for(const int3 &tile : tiles[i])
 		{
@@ -2575,7 +2603,7 @@ int3 VCAI::explorationDesperate(HeroPtr h)
 {
 	auto sm = getCachedSectorMap(h);
 	int radius = h->getSightRadious();
-	
+
 	std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
 	tiles.resize(radius);
 
@@ -2590,10 +2618,10 @@ int3 VCAI::explorationDesperate(HeroPtr h)
 	ui64 lowestDanger = -1;
 	int3 bestTile(-1,-1,-1);
 
-	for (int i = 1; i < radius; i++)
+	for(int i = 1; i < radius; i++)
 	{
 		getVisibleNeighbours(tiles[i-1], tiles[i]);
-		removeDuplicates(tiles[i]);
+		vstd::removeDuplicates(tiles[i]);
 
 		for(const int3 &tile : tiles[i])
 		{
@@ -2705,37 +2733,26 @@ void VCAI::finish()
 
 void VCAI::requestActionASAP(std::function<void()> whatToDo)
 {
-	boost::mutex mutex;
-	mutex.lock();
-
-	boost::thread newThread([&mutex,this,whatToDo]()
+	boost::thread newThread([this,whatToDo]()
 	{
-		setThreadName("VCAI::requestActionASAP::helper");
+		setThreadName("VCAI::requestActionASAP::whatToDo");
 		SET_GLOBAL_STATE(this);
 		boost::shared_lock<boost::shared_mutex> gsLock(cb->getGsMutex());
-		// unlock mutex and allow parent function to exit
-		mutex.unlock();
 		whatToDo();
 	});
-
-	// wait for mutex to unlock and for thread to initialize properly
-	mutex.lock();
-
-	// unlock mutex - boost dislikes destruction of locked mutexes
-	mutex.unlock();
 }
 
 void VCAI::lostHero(HeroPtr h)
 {
     logAi->debugStream() << boost::format("I lost my hero %s. It's best to forget and move on.") % h.name;
 
-	erase_if_present(lockedHeroes, h);
+	vstd::erase_if_present(lockedHeroes, h);
 	for(auto obj : reservedHeroesMap[h])
 	{
-		erase_if_present(reservedObjs, obj); //unreserve all objects for that hero
+		vstd::erase_if_present(reservedObjs, obj); //unreserve all objects for that hero
 	}
-	erase_if_present(reservedHeroesMap, h);
-	erase_if_present(cachedSectorMaps, h);
+	vstd::erase_if_present(reservedHeroesMap, h);
+	vstd::erase_if_present(cachedSectorMaps, h);
 }
 
 void VCAI::answerQuery(QueryID queryID, int selection)
@@ -2776,15 +2793,15 @@ void VCAI::validateObject(const CGObjectInstance *obj)
 
 void VCAI::validateObject(ObjectIdRef obj)
 {
-	auto matchesId = [&] (const CGObjectInstance *hlpObj) -> bool { return hlpObj->id == obj.id; };
+	auto matchesId = [&](const CGObjectInstance *hlpObj) -> bool { return hlpObj->id == obj.id; };
 	if(!obj)
 	{
-		erase_if(visitableObjs, matchesId);
+		vstd::erase_if(visitableObjs, matchesId);
 
 		for(auto &p : reservedHeroesMap)
-			erase_if(p.second, matchesId);
+			vstd::erase_if(p.second, matchesId);
 
-		erase_if(reservedObjs, matchesId);
+		vstd::erase_if(reservedObjs, matchesId);
 	}
 }
 
@@ -2933,8 +2950,8 @@ void AIStatus::heroVisit(const CGObjectInstance *obj, bool started)
 		objectsBeingVisited.push_back(obj);
 	else
 	{
-		// There can be more than one object visited at the time (eg. hero visits Subterranean Gate 
-		// causing visit to hero on the other side. 
+		// There can be more than one object visited at the time (eg. hero visits Subterranean Gate
+		// causing visit to hero on the other side.
 		// However, we are guaranteed that start/end visit notification maintain stack order.
 		assert(!objectsBeingVisited.empty());
 		objectsBeingVisited.pop_back();
@@ -3048,7 +3065,7 @@ void SectorMap::exploreNewSector(crint3 pos, int num, CCallback * cbp)
 							s.embarkmentPoints.push_back(neighPos);
 						}
 					});
-					
+
 					if(t->visitable)
 					{
 						auto obj = t->visitableObjects.front();
@@ -3062,7 +3079,7 @@ void SectorMap::exploreNewSector(crint3 pos, int num, CCallback * cbp)
 		}
 	}
 
-	removeDuplicates(s.embarkmentPoints);
+	vstd::removeDuplicates(s.embarkmentPoints);
 }
 
 void SectorMap::write(crstring fname)
@@ -3104,7 +3121,7 @@ bool isWeeklyRevisitable (const CGObjectInstance * obj)
 bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 {
 	switch (obj->ID)
-	{	
+	{
 		case Obj::TOWN:
 		case Obj::HERO: //never visit our heroes at random
 			return obj->tempOwner != h->tempOwner; //do not visit our towns at random
@@ -3155,7 +3172,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 			return canRecruitCreatures;
 		}
 		case Obj::HILL_FORT:
-		{	
+		{
 			for (auto slot : h->Slots())
 			{
 				if (slot.second->type->upgrades.size())
@@ -3241,21 +3258,6 @@ For ship construction etc, another function (goal?) is needed
 					sectorQueue.push(neigh);
 				}
 			}
-
-			for (auto gate : s->subterraneanGates)
-			{
-				auto gatePair = ai->knownSubterraneanGates.find(gate);
-				if (gatePair != ai->knownSubterraneanGates.end())
-				{
-					//check the other side of gate
-					Sector *neigh = &infoOnSectors[retreiveTile(gatePair->second->visitablePos())];
-					if(!preds[neigh]) //if we didn't come into this sector yet
-					{
-						preds[neigh] = s; //it becomes our new target sector
-						sectorQueue.push(neigh);
-					}
-				}
-			}
 		}
 
 		if(!preds[dest])
@@ -3361,30 +3363,8 @@ For ship construction etc, another function (goal?) is needed
 				//disembark
 				return ret;
 			}
-			else //use subterranean gates
+			else //use subterranean gates - not needed since gates are now handled via Pathfinder
 			{
-				//auto t = findFirstVisitableTile (h, dst);
-				//if (t.valid())
-				//	return t;
-
-				//TODO: pop sectors linked by Subterranean Gate in loop
-
-				auto firstGate = boost::find_if(src->subterraneanGates, [=](const CGObjectInstance * gate) -> bool
-				{
-					//make sure no hero block the way
-					auto pos = ai->knownSubterraneanGates[gate]->visitablePos();
-					const TerrainTile *t = getTile(pos);
-					return t && t->visitableObjects.size() == 1 && t->topVisitableId() == Obj::SUBTERRANEAN_GATE
-						&& retreiveTile(pos) == sectorToReach->id;
-				});
-
-				if(firstGate != src->subterraneanGates.end())
-				{
-					//TODO: pahtfinder can find path through subterranean gates, but this function only reaches closest gate
-					return (*firstGate)->visitablePos();
-				}
-				//TODO
-				//Monolith? Whirlpool? ...
 				return ret;
 				//throw cannotFulfillGoalException("Land-land and water-water inter-sector transitions are not implemented!");
 			}
@@ -3455,7 +3435,7 @@ void SectorMap::makeParentBFS(crint3 source)
 		ui8 &sec = retreiveTile(curPos);
 		assert(sec == mySector); //consider only tiles from the same sector
 		UNUSED(sec);
-	
+
 		foreach_neighbour(curPos, [&](crint3 neighPos)
 		{
 			if(retreiveTile(neighPos) == mySector && !vstd::contains(parent, neighPos))

+ 5 - 5
AI/VCAI/VCAI.h

@@ -93,7 +93,7 @@ struct SectorMap
 	//std::vector<std::vector<std::vector<unsigned char>>> pathfinderSector;
 
 	std::map<int, Sector> infoOnSectors;
-	shared_ptr<boost::multi_array<TerrainTile*, 3>> visibleTiles;
+	std::shared_ptr<boost::multi_array<TerrainTile*, 3>> visibleTiles;
 
 	SectorMap();
 	SectorMap(HeroPtr h);
@@ -129,7 +129,7 @@ public:
 
 	friend class FuzzyHelper;
 
-	std::map<TeleportChannelID, shared_ptr<TeleportChannel> > knownTeleportChannels;
+	std::map<TeleportChannelID, std::shared_ptr<TeleportChannel> > knownTeleportChannels;
 	std::map<const CGObjectInstance *, const CGObjectInstance *> knownSubterraneanGates;
 	ObjectInstanceID destinationTeleport;
 	int3 destinationTeleportPos;
@@ -153,9 +153,9 @@ public:
 	AIStatus status;
 	std::string battlename;
 
-	shared_ptr<CCallback> myCb;
+	std::shared_ptr<CCallback> myCb;
 
-	unique_ptr<boost::thread> makingTurn;
+	std::unique_ptr<boost::thread> makingTurn;
 
 	VCAI(void);
 	~VCAI(void);
@@ -180,7 +180,7 @@ public:
 
 	virtual std::string getBattleAIName() const override;
 
-	virtual void init(shared_ptr<CCallback> CB) override;
+	virtual void init(std::shared_ptr<CCallback> CB) override;
 	virtual void yourTurn() override;
 
 	virtual void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) override; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id

+ 2 - 2
AI/VCAI/main.cpp

@@ -23,7 +23,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
 	strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
 }
 
-extern "C" DLL_EXPORT void GetNewAI(shared_ptr<CGlobalAI> &out)
+extern "C" DLL_EXPORT void GetNewAI(std::shared_ptr<CGlobalAI> &out)
 {
-	out = make_shared<VCAI>();
+	out = std::make_shared<VCAI>();
 }

+ 1 - 1
AUTHORS

@@ -52,5 +52,5 @@ Alexey aka Macron1Robot,                 <>
 Alexander Shishkin aka alexvins,
    * MinGW platform support, modding related programming
 
-Arseniy Shestakov aka SXX,
+Arseniy Shestakov aka SXX,      <[email protected]>
    * pathfinding improvements, programming

+ 4 - 4
CCallback.cpp

@@ -333,22 +333,22 @@ int CCallback::mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance
 		return swapCreatures(s1, s2, p1, p2);
 }
 
-void CCallback::registerGameInterface(shared_ptr<IGameEventsReceiver> gameEvents)
+void CCallback::registerGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents)
 {
 	cl->additionalPlayerInts[*player].push_back(gameEvents);
 }
 
-void CCallback::registerBattleInterface(shared_ptr<IBattleEventsReceiver> battleEvents)
+void CCallback::registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents)
 {
 	cl->additionalBattleInts[*player].push_back(battleEvents);
 }
 
-void CCallback::unregisterGameInterface(shared_ptr<IGameEventsReceiver> gameEvents)
+void CCallback::unregisterGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents)
 {
 	cl->additionalPlayerInts[*player] -= gameEvents;
 }
 
-void CCallback::unregisterBattleInterface(shared_ptr<IBattleEventsReceiver> battleEvents)
+void CCallback::unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents)
 {
 	cl->additionalBattleInts[*player] -= battleEvents;
 }

+ 4 - 4
CCallback.h

@@ -110,10 +110,10 @@ public:
 	virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out);
 
 	//Set of metrhods that allows adding more interfaces for this player that'll receive game event call-ins.
-	void registerGameInterface(shared_ptr<IGameEventsReceiver> gameEvents);
-	void registerBattleInterface(shared_ptr<IBattleEventsReceiver> battleEvents);
-	void unregisterGameInterface(shared_ptr<IGameEventsReceiver> gameEvents);
-	void unregisterBattleInterface(shared_ptr<IBattleEventsReceiver> battleEvents);
+	void registerGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents);
+	void registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents);
+	void unregisterGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents);
+	void unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents);
 
 	void unregisterAllInterfaces(); //stops delivering information about game events to player interfaces -> can be called ONLY after victory/loss
 

+ 1 - 1
CMakeLists.txt

@@ -64,7 +64,7 @@ endif()
 if (WIN32)
 	add_definitions(-DBOOST_THREAD_USE_LIB)
 	add_definitions(-D_WIN32_WINNT=0x0501)
-	set(SYSTEM_LIBS ${SYSTEM_LIBS} ole32 oleaut32 ws2_32 mswsock)
+	set(SYSTEM_LIBS ${SYSTEM_LIBS} ole32 oleaut32 ws2_32 mswsock dbghelp)
 
 	#delete lib prefix for dlls (libvcmi -> vcmi)
 	set(CMAKE_SHARED_LIBRARY_PREFIX "") 

+ 1 - 3
Global.h

@@ -93,6 +93,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #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.
+#  define _NO_W32_PSEUDO_MODIFIERS  // Exclude more macros for compiling with MinGW on Linux.
 #endif
 
 /* ---------------------------------------------------------------------------- */
@@ -179,9 +180,6 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 /* ---------------------------------------------------------------------------- */
 /* Usings */
 /* ---------------------------------------------------------------------------- */
-using std::shared_ptr;
-using std::unique_ptr;
-using std::make_shared;
 using namespace std::placeholders;
 namespace range = boost::range;
 

+ 25 - 12
client/CMT.cpp

@@ -170,9 +170,9 @@ static void prog_version(void)
 static void prog_help(const po::options_description &opts)
 {
 	printf("%s - A Heroes of Might and Magic 3 clone\n", GameConstants::VCMI_VERSION.c_str());
-    printf("Copyright (C) 2007-2014 VCMI dev team - see AUTHORS file\n");
-    printf("This is free software; see the source for copying conditions. There is NO\n");
-    printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+	printf("Copyright (C) 2007-2016 VCMI dev team - see AUTHORS file\n");
+	printf("This is free software; see the source for copying conditions. There is NO\n");
+	printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
 	printf("\n");
 	printf("Usage:\n");
 	std::cout << opts;
@@ -244,7 +244,9 @@ int main(int argc, char** argv)
         ("loadhumanplayerindices",po::value<std::vector<int>>(),"Indexes of human players (0=Red, etc.)")
         ("loadplayer", po::value<int>(),"specifies which player we are in multiplayer loaded games (0=Red, etc.)")
         ("loadserverip",po::value<std::string>(),"IP for loaded game server")
-        ("loadserverport",po::value<std::string>(),"port for loaded game server");
+		("loadserverport",po::value<std::string>(),"port for loaded game server")
+		("testingport",po::value<std::string>(),"port for testing, override specified in config file")
+		("testingfileprefix",po::value<std::string>(),"prefix for auto save files");
 
 	if(argc > 1)
 	{
@@ -281,7 +283,7 @@ int main(int argc, char** argv)
 	// it may result in very small \ very fast mouse when game in fullscreen mode
 	putenv((char*)"SDL_VIDEO_X11_DGAMOUSE=0");
 
-    // Init old logging system and new (temporary) logging system
+	// Init old logging system and new (temporary) logging system
 	CStopWatch total, pomtime;
 	std::cout.flags(std::ios::unitbuf);
 	console = new CConsoleHandler;
@@ -291,16 +293,25 @@ int main(int argc, char** argv)
 
 	const bfs::path logPath = VCMIDirs::get().userCachePath() / "VCMI_Client_log.txt";
 	CBasicLogConfigurator logConfig(logPath, console);
-    logConfig.configureDefault();
+	logConfig.configureDefault();
 	logGlobal->infoStream() << "Creating console and configuring logger: " << pomtime.getDiff();
 	logGlobal->infoStream() << "The log file will be saved to " << logPath;
 
-    // Init filesystem and settings
+	// Init filesystem and settings
 	preinitDLL(::console);
-    settings.init();
+	settings.init();
 
-    // Initialize logging based on settings
-    logConfig.configure();
+	// Init special testing settings
+	Settings testingSettings = settings.write["testing"];
+	if(vm.count("testingport") && vm.count("testingfileprefix"))
+	{
+		testingSettings["enabled"].Bool() = true;
+		testingSettings["port"].String() = vm["testingport"].as<std::string>();
+		testingSettings["prefix"].String() = vm["testingfileprefix"].as<std::string>();
+	}
+
+	// Initialize logging based on settings
+	logConfig.configure();
 
 	// Some basic data validation to produce better error messages in cases of incorrect install
 	auto testFile = [](std::string filename, std::string message) -> bool
@@ -308,13 +319,15 @@ int main(int argc, char** argv)
 		if (CResourceHandler::get()->existsResource(ResourceID(filename)))
 			return true;
 
-        logGlobal->errorStream() << "Error: " << message << " was not found!";
+		logGlobal->errorStream() << "Error: " << message << " was not found!";
 		return false;
 	};
 
 	if (!testFile("DATA/HELP.TXT", "Heroes III data") ||
-	    !testFile("MODS/VCMI/MOD.JSON", "VCMI data"))
+		!testFile("MODS/VCMI/MOD.JSON", "VCMI data"))
+	{
 		exit(1); // These are unrecoverable errors
+	}
 
 	// these two are optional + some installs have them on CD and not in data directory
 	testFile("VIDEO/GOOD1A.SMK", "campaign movies");

+ 1 - 1
client/CMusicHandler.cpp

@@ -349,7 +349,7 @@ void CMusicHandler::playMusicFromSet(std::string whichSet, int entryID, bool loo
 	queueNext(this, "", selectedEntry->second, loop);
 }
 
-void CMusicHandler::queueNext(unique_ptr<MusicEntry> queued)
+void CMusicHandler::queueNext(std::unique_ptr<MusicEntry> queued)
 {
 	if (!initialized)
 		return;

+ 3 - 3
client/CMusicHandler.h

@@ -114,11 +114,11 @@ private:
 	SettingsListener listener;
 	void onVolumeChange(const JsonNode &volumeNode);
 
-	unique_ptr<MusicEntry> current;
-	unique_ptr<MusicEntry> next;
+	std::unique_ptr<MusicEntry> current;
+	std::unique_ptr<MusicEntry> next;
 	
 	void queueNext(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped);
-	void queueNext(unique_ptr<MusicEntry> queued);
+	void queueNext(std::unique_ptr<MusicEntry> queued);
 
 	std::map<std::string, std::map<int, std::string> > musicsSet;
 public:

+ 53 - 12
client/CPlayerInterface.cpp

@@ -133,7 +133,7 @@ CPlayerInterface::~CPlayerInterface()
 	if(LOCPLINT == this)
 		LOCPLINT = nullptr;
 }
-void CPlayerInterface::init(shared_ptr<CCallback> CB)
+void CPlayerInterface::init(std::shared_ptr<CCallback> CB)
 {
 	cb = CB;
 	if(observerInDuelMode)
@@ -157,24 +157,30 @@ void CPlayerInterface::yourTurn()
 		GH.curInt = this;
 		adventureInt->selection = nullptr;
 
+		std::string prefix = "";
+		if(settings["testing"]["enabled"].Bool())
+		{
+			prefix = settings["testing"]["prefix"].String();
+		}
+
 		if(firstCall)
 		{
 			if(howManyPeople == 1)
 				adventureInt->setPlayer(playerID);
 
-			autosaveCount = getLastIndex("Autosave_");
+			autosaveCount = getLastIndex(prefix + "Autosave_");
 
 			if(firstCall > 0) //new game, not loaded
 			{
-				int index = getLastIndex("Newgame_Autosave_");
+				int index = getLastIndex(prefix + "Newgame_");
 				index %= SAVES_COUNT;
-				cb->save("Saves/Newgame_Autosave_" + boost::lexical_cast<std::string>(index + 1));
+				cb->save("Saves/" + prefix + "Newgame_Autosave_" + boost::lexical_cast<std::string>(index + 1));
 			}
 			firstCall = 0;
 		}
 		else
 		{
-			LOCPLINT->cb->save("Saves/Autosave_" + boost::lexical_cast<std::string>(autosaveCount++ + 1));
+			LOCPLINT->cb->save("Saves/" + prefix + "Autosave_" + boost::lexical_cast<std::string>(autosaveCount++ + 1));
 			autosaveCount %= 5;
 		}
 
@@ -2242,8 +2248,10 @@ CGPath * CPlayerInterface::getAndVerifyPath(const CGHeroInstance * h)
 
 void CPlayerInterface::acceptTurn()
 {
+	bool centerView = true;
 	if(settings["session"]["autoSkip"].Bool())
 	{
+		centerView = false;
 		while(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt()))
 			iw->close();
 	}
@@ -2270,10 +2278,10 @@ void CPlayerInterface::acceptTurn()
 	//select first hero if available.
 	if(heroToSelect != nullptr)
 	{
-		adventureInt->select(heroToSelect);
+		adventureInt->select(heroToSelect, centerView);
 	}
 	else
-		adventureInt->select(towns.front());
+		adventureInt->select(towns.front(), centerView);
 
 	//show new day animation and sound on infobar
 	adventureInt->infoBar.showDate();
@@ -2629,6 +2637,31 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
 		return cb->getTile(CGHeroInstance::convertPosition(coord,false))->topVisitableObj(ignoreHero);
 	};
 
+	auto isTeleportAction = [&](CGPathNode::ENodeAction action) -> bool
+	{
+		if(action != CGPathNode::TELEPORT_NORMAL &&
+			action != CGPathNode::TELEPORT_BLOCKING_VISIT &&
+			action != CGPathNode::TELEPORT_BATTLE)
+		{
+			return false;
+		}
+
+		return true;
+	};
+
+	auto getDestTeleportObj = [&](const CGObjectInstance * currentObject, const CGObjectInstance * nextObjectTop, const CGObjectInstance * nextObject) -> const CGObjectInstance *
+	{
+		if(CGTeleport::isConnected(currentObject, nextObjectTop))
+			return nextObjectTop;
+		if(nextObjectTop && nextObjectTop->ID == Obj::HERO &&
+			CGTeleport::isConnected(currentObject, nextObject))
+		{
+			return nextObject;
+		}
+
+		return nullptr;
+	};
+
 	boost::unique_lock<boost::mutex> un(stillMoveHero.mx);
 	stillMoveHero.data = CONTINUE_MOVE;
 	auto doMovement = [&](int3 dst, bool transit)
@@ -2661,13 +2694,21 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
 			int3 currentCoord = path.nodes[i].coord;
 			int3 nextCoord = path.nodes[i-1].coord;
 
-			auto nextObject = getObj(nextCoord, nextCoord == h->pos);
-			if(CGTeleport::isConnected(getObj(currentCoord, currentCoord == h->pos), nextObject))
+			auto currentObject = getObj(currentCoord, currentCoord == h->pos);
+			auto nextObjectTop = getObj(nextCoord, false);
+			auto nextObject = getObj(nextCoord, true);
+			auto destTeleportObj = getDestTeleportObj(currentObject, nextObjectTop, nextObject);
+			if(isTeleportAction(path.nodes[i-1].action) && destTeleportObj != nullptr)
 			{
 				CCS->soundh->stopSound(sh);
-				destinationTeleport = nextObject->id;
+				destinationTeleport = destTeleportObj->id;
 				destinationTeleportPos = nextCoord;
 				doMovement(h->pos, false);
+				if(path.nodes[i-1].action == CGPathNode::TELEPORT_BLOCKING_VISIT)
+				{
+					destinationTeleport = ObjectInstanceID();
+					destinationTeleportPos = int3(-1);
+				}
 				sh = CCS->soundh->playSound(CCS->soundh->horseSounds[currentTerrain], -1);
 				continue;
 			}
@@ -2700,8 +2741,8 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
 
 			bool useTransit = false;
 			if((i-2 >= 0) // Check there is node after next one; otherwise transit is pointless
-				&& (CGTeleport::isConnected(nextObject, getObj(path.nodes[i-2].coord, false))
-					|| CGTeleport::isTeleport(nextObject)))
+				&& (CGTeleport::isConnected(nextObjectTop, getObj(path.nodes[i-2].coord, false))
+					|| CGTeleport::isTeleport(nextObjectTop)))
 			{ // Hero should be able to go through object if it's allow transit
 				useTransit = true;
 			}

+ 3 - 3
client/CPlayerInterface.h

@@ -105,7 +105,7 @@ public:
 	static CBattleInterface * battleInt; //nullptr if no battle
 	CInGameConsole * cingconsole;
 
-	shared_ptr<CCallback> cb; //to communicate with engine
+	std::shared_ptr<CCallback> cb; //to communicate with engine
 	const BattleAction *curAction; //during the battle - action currently performed by active stack (or nullptr)
 
 	std::list<CInfoWindow *> dialogs; //queue of dialogs awaiting to be shown (not currently shown!)
@@ -116,7 +116,7 @@ public:
 	std::vector<const CGHeroInstance *> sleepingHeroes; //if hero is in here, he's sleeping
 
 	//During battle is quick combat mode is used
-	shared_ptr<CBattleGameInterface> autofightingAI; //AI that makes decisions
+	std::shared_ptr<CBattleGameInterface> autofightingAI; //AI that makes decisions
 	bool isAutoFightOn; //Flag, switch it to stop quick combat. Don't touch if there is no battle interface.
 
 	const CArmedInstance * getSelection();
@@ -236,7 +236,7 @@ public:
 	void openTownWindow(const CGTownInstance * town); //shows townscreen
 	void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero
 	void updateInfo(const CGObjectInstance * specific);
-	void init(shared_ptr<CCallback> CB) override;
+	void init(std::shared_ptr<CCallback> CB) override;
 	int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
 
 	// show dialogs

+ 3 - 3
client/CPreGame.cpp

@@ -1918,7 +1918,7 @@ const CMapGenOptions & CRandomMapTab::getMapGenOptions() const
 	return mapGenOptions;
 }
 
-void CRandomMapTab::setMapGenOptions(shared_ptr<CMapGenOptions> opts)
+void CRandomMapTab::setMapGenOptions(std::shared_ptr<CMapGenOptions> opts)
 {
 	mapSizeBtnGroup->setSelected(vstd::find_pos(getPossibleMapSizes(), opts->getWidth()));
 	twoLevelsBtn->setSelected(opts->getHasTwoLevels());
@@ -3291,14 +3291,14 @@ void CBonusSelection::init()
 	sFlags = CDefHandler::giveDef("ITGFLAGS.DEF");
 }
 
-CBonusSelection::CBonusSelection(shared_ptr<CCampaignState> _ourCampaign) : ourCampaign(_ourCampaign)
+CBonusSelection::CBonusSelection(std::shared_ptr<CCampaignState> _ourCampaign) : ourCampaign(_ourCampaign)
 {
 	init();
 }
 
 CBonusSelection::CBonusSelection(const std::string & campaignFName)
 {
-	ourCampaign = make_shared<CCampaignState>(CCampaignHandler::getCampaign(campaignFName));
+	ourCampaign = std::make_shared<CCampaignState>(CCampaignHandler::getCampaign(campaignFName));
 	init();
 }
 

+ 4 - 4
client/CPreGame.h

@@ -300,7 +300,7 @@ public:
 	CFunctionList<void (const CMapInfo *)> & getMapInfoChanged();
 	const CMapInfo * getMapInfo() const;
 	const CMapGenOptions & getMapGenOptions() const;
-	void setMapGenOptions(shared_ptr<CMapGenOptions> opts);
+	void setMapGenOptions(std::shared_ptr<CMapGenOptions> opts);
 
 private:
     void addButtonsToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex) const;
@@ -316,7 +316,7 @@ private:
 		* compOnlyTeamsCntGroup, * waterContentGroup, * monsterStrengthGroup;
     CButton * showRandMaps;
 	CMapGenOptions mapGenOptions;
-	unique_ptr<CMapInfo> mapInfo;
+	std::unique_ptr<CMapInfo> mapInfo;
 	CFunctionList<void(const CMapInfo *)> mapInfoChanged;
 };
 
@@ -463,7 +463,7 @@ class CBonusSelection : public CIntObject
 {
 public:
 	CBonusSelection(const std::string & campaignFName);
-	CBonusSelection(shared_ptr<CCampaignState> _ourCampaign);
+	CBonusSelection(std::shared_ptr<CCampaignState> _ourCampaign);
 	~CBonusSelection();
 
 	void showAll(SDL_Surface * to) override;
@@ -532,7 +532,7 @@ private:
 	CDefHandler * sFlags;
 
 	// Data
-	shared_ptr<CCampaignState> ourCampaign;
+	std::shared_ptr<CCampaignState> ourCampaign;
 	int selectedMap;
 	boost::optional<int> selectedBonus;
 	StartInfo startInfo;

+ 43 - 25
client/Client.cpp

@@ -246,18 +246,25 @@ void CClient::endGame( bool closeConnection /*= true*/ )
 #if 1
 void CClient::loadGame(const std::string & fname, const bool server, const std::vector<int>& humanplayerindices, const int loadNumPlayers, int player_, const std::string & ipaddr, const std::string & port)
 {
-    PlayerColor player(player_); //intentional shadowing
-
-    logNetwork->infoStream() <<"Loading procedure started!";
+	PlayerColor player(player_); //intentional shadowing
+	logNetwork->infoStream() << "Loading procedure started!";
+
+	std::string realPort;
+	if(settings["testing"]["enabled"].Bool())
+		realPort = settings["testing"]["port"].String();
+	else if(port.size())
+		realPort = port;
+	else
+		realPort = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
 
 	CServerHandler sh;
-    if(server)
-         sh.startServer();
-    else
-         serv = sh.justConnectToServer(ipaddr,port=="" ? "3030" : port);
+	if(server)
+		sh.startServer();
+	else
+		serv = sh.justConnectToServer(ipaddr, realPort);
 
 	CStopWatch tmh;
-    unique_ptr<CLoadFile> loader;
+	std::unique_ptr<CLoadFile> loader;
 	try
 	{
 		std::string clientSaveName = *CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::CLIENT_SAVEGAME));
@@ -454,7 +461,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 			}
 			else 
 			{
-				installNewPlayerInterface(make_shared<CPlayerInterface>(color), color);
+				installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color);
 				humanPlayers++;
 			}
 		}
@@ -470,7 +477,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 		if(!gNoGUI)
 		{
 			boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
-			auto p = make_shared<CPlayerInterface>(PlayerColor::NEUTRAL);
+			auto p = std::make_shared<CPlayerInterface>(PlayerColor::NEUTRAL);
 			p->observerInDuelMode = true;
 			installNewPlayerInterface(p, boost::none);
 			GH.curInt = p.get();
@@ -535,7 +542,7 @@ void CClient::serialize(CISer & h, const int version)
 			h & pid & dllname & isHuman;
 			LOG_TRACE_PARAMS(logGlobal, "Loading player %s interface", pid);
 
-			shared_ptr<CGameInterface> nInt;
+			std::shared_ptr<CGameInterface> nInt;
 			if(dllname.length())
 			{
 				if(pid == PlayerColor::NEUTRAL)
@@ -553,7 +560,7 @@ void CClient::serialize(CISer & h, const int version)
 			else
 			{
 				assert(isHuman);
-				nInt = make_shared<CPlayerInterface>(pid);
+				nInt = std::make_shared<CPlayerInterface>(pid);
 			}
 
 			nInt->dllName = dllname;
@@ -604,7 +611,7 @@ void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor
 			h & pid & dllname & isHuman;
 			LOG_TRACE_PARAMS(logGlobal, "Loading player %s interface", pid);
 
-			shared_ptr<CGameInterface> nInt;
+			std::shared_ptr<CGameInterface> nInt;
 			if(dllname.length())
 			{
 				if(pid == PlayerColor::NEUTRAL)
@@ -623,7 +630,7 @@ void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor
 			else
 			{
 				assert(isHuman);
-				nInt = make_shared<CPlayerInterface>(pid);
+				nInt = std::make_shared<CPlayerInterface>(pid);
 			}
 
 			nInt->dllName = dllname;
@@ -661,11 +668,11 @@ void CClient::handlePack( CPack * pack )
 	delete pack;
 }
 
-void CClient::finishCampaign( shared_ptr<CCampaignState> camp )
+void CClient::finishCampaign( std::shared_ptr<CCampaignState> camp )
 {
 }
 
-void CClient::proposeNextMission(shared_ptr<CCampaignState> camp)
+void CClient::proposeNextMission(std::shared_ptr<CCampaignState> camp)
 {
 	GH.pushInt(new CBonusSelection(camp));
 }
@@ -717,7 +724,7 @@ void CClient::battleStarted(const BattleInfo * info)
 // 		if(battleCallbacks.count(side))
 // 			battleCallbacks[side]->setBattle(info);
 
-	shared_ptr<CPlayerInterface> att, def;
+	std::shared_ptr<CPlayerInterface> att, def;
 	auto &leftSide = info->sides[0], &rightSide = info->sides[1];
 
 
@@ -783,7 +790,7 @@ PlayerColor CClient::getLocalPlayer() const
 	return getCurrentPlayer();
 }
 
-void CClient::commenceTacticPhaseForInt(shared_ptr<CBattleGameInterface> battleInt)
+void CClient::commenceTacticPhaseForInt(std::shared_ptr<CBattleGameInterface> battleInt)
 {
 	setThreadName("CClient::commenceTacticPhaseForInt");
 	try
@@ -835,7 +842,7 @@ int CClient::sendRequest(const CPack *request, PlayerColor player)
 	return requestID;
 }
 
-void CClient::campaignMapFinished( shared_ptr<CCampaignState> camp )
+void CClient::campaignMapFinished( std::shared_ptr<CCampaignState> camp )
 {
 	endGame(false);
 
@@ -858,7 +865,7 @@ void CClient::campaignMapFinished( shared_ptr<CCampaignState> camp )
 	}
 }
 
-void CClient::installNewPlayerInterface(shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color)
+void CClient::installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
 	PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
@@ -869,7 +876,7 @@ void CClient::installNewPlayerInterface(shared_ptr<CGameInterface> gameInterface
 	playerint[colorUsed] = gameInterface;
 
 	logGlobal->traceStream() << boost::format("\tInitializing the interface for player %s") % colorUsed;
-	auto cb = make_shared<CCallback>(gs, color, this);
+	auto cb = std::make_shared<CCallback>(gs, color, this);
 	callbacks[colorUsed] = cb;
 	battleCallbacks[colorUsed] = cb;
 	gameInterface->init(cb);
@@ -877,7 +884,7 @@ void CClient::installNewPlayerInterface(shared_ptr<CGameInterface> gameInterface
 	installNewBattleInterface(gameInterface, color, false);
 }
 
-void CClient::installNewBattleInterface(shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback /*= true*/)
+void CClient::installNewBattleInterface(std::shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback /*= true*/)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
 	PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
@@ -890,7 +897,7 @@ void CClient::installNewBattleInterface(shared_ptr<CBattleGameInterface> battleI
 	if(needCallback)
 	{
 		logGlobal->traceStream() << boost::format("\tInitializing the battle interface for player %s") % *color;
-		auto cbc = make_shared<CBattleCallback>(gs, color, this);
+		auto cbc = std::make_shared<CBattleCallback>(gs, color, this);
 		battleCallbacks[colorUsed] = cbc;
 		battleInterface->init(cbc);
 	}
@@ -967,7 +974,10 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
 {
 	serverThread = nullptr;
 	shared = nullptr;
-	port = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
+	if(settings["testing"]["enabled"].Bool())
+		port = settings["testing"]["port"].String();
+	else
+		port = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
 	verbose = true;
 
 #ifndef VCMI_ANDROID
@@ -1009,6 +1019,14 @@ void CServerHandler::callServer()
 
 CConnection * CServerHandler::justConnectToServer(const std::string &host, const std::string &port)
 {
+	std::string realPort;
+	if(settings["testing"]["enabled"].Bool())
+		realPort = settings["testing"]["port"].String();
+	else if(port.size())
+		realPort = port;
+	else
+		realPort = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
+
 	CConnection *ret = nullptr;
 	while(!ret)
 	{
@@ -1016,7 +1034,7 @@ CConnection * CServerHandler::justConnectToServer(const std::string &host, const
 		{
             logNetwork->infoStream() << "Establishing connection...";
 			ret = new CConnection(	host.size() ? host : settings["server"]["server"].String(), 
-									port.size() ? port : boost::lexical_cast<std::string>(settings["server"]["port"].Float()), 
+									realPort,
 									NAME);
 		}
 		catch(...)

+ 15 - 15
client/Client.h

@@ -115,17 +115,17 @@ public:
 /// Class which handles client - server logic
 class CClient : public IGameCallback
 {
-	unique_ptr<CPathsInfo> pathInfo;
+	std::unique_ptr<CPathsInfo> pathInfo;
 public:
-	std::map<PlayerColor,shared_ptr<CCallback> > callbacks; //callbacks given to player interfaces
-	std::map<PlayerColor,shared_ptr<CBattleCallback> > battleCallbacks; //callbacks given to player interfaces
-	std::vector<shared_ptr<IGameEventsReceiver>> privilagedGameEventReceivers; //scripting modules, spectator interfaces
-	std::vector<shared_ptr<IBattleEventsReceiver>> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
-	std::map<PlayerColor, shared_ptr<CGameInterface>> playerint;
-	std::map<PlayerColor, shared_ptr<CBattleGameInterface>> battleints;
+	std::map<PlayerColor,std::shared_ptr<CCallback> > callbacks; //callbacks given to player interfaces
+	std::map<PlayerColor,std::shared_ptr<CBattleCallback> > battleCallbacks; //callbacks given to player interfaces
+	std::vector<std::shared_ptr<IGameEventsReceiver>> privilagedGameEventReceivers; //scripting modules, spectator interfaces
+	std::vector<std::shared_ptr<IBattleEventsReceiver>> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
+	std::map<PlayerColor, std::shared_ptr<CGameInterface>> playerint;
+	std::map<PlayerColor, std::shared_ptr<CBattleGameInterface>> battleints;
 
-	std::map<PlayerColor,std::vector<shared_ptr<IGameEventsReceiver>>> additionalPlayerInts;
-	std::map<PlayerColor,std::vector<shared_ptr<IBattleEventsReceiver>>> additionalBattleInts;
+	std::map<PlayerColor,std::vector<std::shared_ptr<IGameEventsReceiver>>> additionalPlayerInts;
+	std::map<PlayerColor,std::vector<std::shared_ptr<IBattleEventsReceiver>>> additionalBattleInts;
 
 	bool hotSeat;
 	CConnection *serv;
@@ -146,8 +146,8 @@ public:
 	void newGame(CConnection *con, StartInfo *si); //con - connection to server
 
 	void loadNeutralBattleAI();
-	void installNewPlayerInterface(shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color);
-	void installNewBattleInterface(shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback = true);
+	void installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color);
+	void installNewBattleInterface(std::shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback = true);
 	std::string aiNameForPlayer(const PlayerSettings &ps, bool battleAI); //empty means no AI -> human
 
 	void endGame(bool closeConnection = true);
@@ -155,9 +155,9 @@ public:
 	void save(const std::string & fname);
 	void loadGame(const std::string & fname, const bool server = true, const std::vector<int>& humanplayerindices = std::vector<int>(), const int loadnumplayers = 1, int player_ = -1, const std::string & ipaddr = "", const std::string & port = "");
 	void run();
-	void campaignMapFinished( shared_ptr<CCampaignState> camp );
-	void finishCampaign( shared_ptr<CCampaignState> camp );
-	void proposeNextMission(shared_ptr<CCampaignState> camp);
+	void campaignMapFinished( std::shared_ptr<CCampaignState> camp );
+	void finishCampaign( std::shared_ptr<CCampaignState> camp );
+	void proposeNextMission(std::shared_ptr<CCampaignState> camp);
 
 	void invalidatePaths();
 	const CPathsInfo * getPathsInfo(const CGHeroInstance *h);
@@ -233,7 +233,7 @@ public:
 
 	void handlePack( CPack * pack ); //applies the given pack and deletes it
 	void battleStarted(const BattleInfo * info);
-	void commenceTacticPhaseForInt(shared_ptr<CBattleGameInterface> battleInt); //will be called as separate thread
+	void commenceTacticPhaseForInt(std::shared_ptr<CBattleGameInterface> battleInt); //will be called as separate thread
 
 	void commitPackage(CPackForClient *pack) override;
 

+ 2 - 2
client/battle/CBattleInterface.cpp

@@ -95,7 +95,7 @@ void CBattleInterface::addNewAnim(CBattleAnimation * anim)
 CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2,
 								   const CGHeroInstance *hero1, const CGHeroInstance *hero2,
 								   const SDL_Rect & myRect,
-								   shared_ptr<CPlayerInterface> att, shared_ptr<CPlayerInterface> defen)
+								   std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen)
 	: background(nullptr), queue(nullptr), attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0),
       activeStack(nullptr), mouseHoveredStack(nullptr), stackToActivate(nullptr), selectedStack(nullptr), previouslyHoveredHex(-1),
 	  currentlyHoveredHex(-1), attackingHex(-1), stackCanCastSpell(false), creatureCasting(false), spellDestSelectMode(false), spellSelMode(NO_LOCATION), spellToCast(nullptr), sp(nullptr),
@@ -3260,7 +3260,7 @@ void CBattleInterface::showStacks(SDL_Surface * to, std::vector<const CStack *>
 	}
 }
 
-void CBattleInterface::showObstacles(SDL_Surface *to, std::vector<shared_ptr<const CObstacleInstance> > &obstacles)
+void CBattleInterface::showObstacles(SDL_Surface *to, std::vector<std::shared_ptr<const CObstacleInstance> > &obstacles)
 {
 	for (auto & obstacle : obstacles)
 	{

+ 6 - 6
client/battle/CBattleInterface.h

@@ -79,7 +79,7 @@ struct BattleObjectsByHex
 	typedef std::vector<int> TWallList;
 	typedef std::vector<const CStack * > TStackList;
 	typedef std::vector<const BattleEffect *> TEffectList;
-	typedef std::vector<shared_ptr<const CObstacleInstance> > TObstacleList;
+	typedef std::vector<std::shared_ptr<const CObstacleInstance> > TObstacleList;
 
 	struct HexData
 	{
@@ -153,7 +153,7 @@ private:
 	BattleHex currentlyHoveredHex; //number of hex that is supposed to be hovered (for a while it may be inappropriately set, but will be renewed soon)
 	int attackingHex; //hex from which the stack would perform attack with current cursor
 
-	shared_ptr<CPlayerInterface> tacticianInterface; //used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players
+	std::shared_ptr<CPlayerInterface> tacticianInterface; //used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players
 	bool tacticsMode;
 	bool stackCanCastSpell; //if true, active stack could possibly cast some target spell
 	bool creatureCasting; //if true, stack currently aims to cats a spell
@@ -212,8 +212,8 @@ private:
 		friend class CBattleInterface;
 	} * siegeH;
 
-	shared_ptr<CPlayerInterface> attackerInt, defenderInt; //because LOCPLINT is not enough in hotSeat
-	shared_ptr<CPlayerInterface> curInt; //current player interface
+	std::shared_ptr<CPlayerInterface> attackerInt, defenderInt; //because LOCPLINT is not enough in hotSeat
+	std::shared_ptr<CPlayerInterface> curInt; //current player interface
 	const CGHeroInstance * getActiveHero(); //returns hero that can currently cast a spell
 
 	/** Methods for displaying battle screen */
@@ -229,7 +229,7 @@ private:
 
 	void showAliveStacks(SDL_Surface * to, std::vector<const CStack *> stacks);
 	void showStacks(SDL_Surface * to, std::vector<const CStack *> stacks);
-	void showObstacles(SDL_Surface *to, std::vector<shared_ptr<const CObstacleInstance> > &obstacles);
+	void showObstacles(SDL_Surface *to, std::vector<std::shared_ptr<const CObstacleInstance> > &obstacles);
 	void showPiecesOfWall(SDL_Surface * to, std::vector<int> pieces);
 
 	void showBattleEffects(SDL_Surface *to, const std::vector<const BattleEffect *> &battleEffects);
@@ -249,7 +249,7 @@ public:
 	ui32 animIDhelper; //for giving IDs for animations
 	static CondSh<bool> animsAreDisplayed; //for waiting with the end of battle for end of anims
 
-	CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, const SDL_Rect & myRect, shared_ptr<CPlayerInterface> att, shared_ptr<CPlayerInterface> defen); //c-tor
+	CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, const SDL_Rect & myRect, std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen); //c-tor
 	~CBattleInterface(); //d-tor
 
 	//std::vector<TimeInterested*> timeinterested; //animation handling

+ 1 - 1
client/battle/CCreatureAnimation.h

@@ -66,7 +66,7 @@ private:
 
 	//animation raw data
 	//TODO: use vector instead?
-	unique_ptr<ui8[]> pixelData;
+	std::unique_ptr<ui8[]> pixelData;
 	size_t pixelDataSize;
 
 	// speed of animation, measure in frames per second

+ 1 - 1
client/mapHandler.cpp

@@ -1576,7 +1576,7 @@ void CMapHandler::getTerrainDescr( const int3 &pos, std::string & out, bool terN
 		}
 	}
 
-	if(t.hasFavourableWinds())
+	if(t.hasFavorableWinds())
 		out = CGI->objtypeh->getObjectName(Obj::FAVORABLE_WINDS);
 	else if(terName)
 	{

+ 10 - 1
client/widgets/MiscWidgets.cpp

@@ -380,7 +380,16 @@ void MoraleLuckBox::set(const IBonusBearer *node)
 	if (morale && node && (node->hasBonusOfType(Bonus::UNDEAD) 
 			|| node->hasBonusOfType(Bonus::BLOCK_MORALE) 
 			|| node->hasBonusOfType(Bonus::NON_LIVING)))
-		text += CGI->generaltexth->arraytxt[113]; //unaffected by morale		
+	{
+		text += CGI->generaltexth->arraytxt[113]; //unaffected by morale
+		bonusValue = 0;
+	}
+	else if(!morale && node && node->hasBonusOfType(Bonus::BLOCK_LUCK))
+	{
+		// TODO: there is no text like "Unaffected by luck" so probably we need own text
+		text += CGI->generaltexth->arraytxt[noneTxtId];
+		bonusValue = 0;
+	}
 	else if(modifierList->empty())
 		text += CGI->generaltexth->arraytxt[noneTxtId];//no modifiers
 	else

+ 29 - 18
client/windows/CAdvmapInterface.cpp

@@ -55,16 +55,15 @@
  */
 
 #define ADVOPT (conf.go()->ac)
-using namespace boost::logic;
 using namespace CSDL_Ext;
 
 CAdvMapInt *adventureInt;
 
 
 CTerrainRect::CTerrainRect()
-	: fadeSurface(nullptr), 
+	: fadeSurface(nullptr),
 	  fadeAnim(new CFadeAnimation()),
-	  curHoveredTile(-1,-1,-1), 
+	  curHoveredTile(-1,-1,-1),
 	  currentPath(nullptr)
 {
 	tilesw=(ADVOPT.advmapW+31)/32;
@@ -283,7 +282,7 @@ void CTerrainRect::show(SDL_Surface * to)
 		info.heroAnim = adventureInt->heroAnim;
 		if (ADVOPT.smoothMove)
 			info.movement = int3(moveX, moveY, 0);
-		
+
 		lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info);
 		if (fadeAnim->isFading())
 		{
@@ -316,7 +315,7 @@ void CTerrainRect::showAll(SDL_Surface * to)
 }
 
 void CTerrainRect::showAnim(SDL_Surface * to)
-{	
+{
 	if (fadeAnim->isFading())
 		show(to);
 	else if (lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED)
@@ -357,7 +356,7 @@ void CTerrainRect::fadeFromCurrentView()
 		return;
 	if (adventureInt->mode == EAdvMapMode::WORLD_VIEW)
 		return;
-	
+
 	if (!fadeSurface)
 		fadeSurface = CSDL_Ext::newSurface(pos.w, pos.h);
 	SDL_BlitSurface(screen, &pos, fadeSurface, nullptr);
@@ -502,10 +501,10 @@ CAdvMapInt::CAdvMapInt():
 	endTurn      = makeButton(302, std::bind(&CAdvMapInt::fendTurn,this),          ADVOPT.endTurn,      SDLK_e);
 
 	int panelSpaceBottom = screen->h - resdatabar.pos.h - 4;
-	
+
 	panelMain = new CAdvMapPanel(nullptr, Point(0, 0));
 	// TODO correct drawing position
-	panelWorldView = new CAdvMapWorldViewPanel(bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID); 
+	panelWorldView = new CAdvMapWorldViewPanel(bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID);
 
 	panelMain->addChildColorableButton(kingOverview);
 	panelMain->addChildColorableButton(underground);
@@ -593,7 +592,7 @@ CAdvMapInt::CAdvMapInt():
 											Colors::WHITE, CGI->generaltexth->allTexts[618]));
 
 	activeMapPanel = panelMain;
-	
+
 	changeMode(EAdvMapMode::NORMAL);
 
 	underground->block(!CGI->mh->map->twoLevel);
@@ -767,6 +766,11 @@ void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath)
 	moveHero->block(!hasPath || (h->movement == 0));
 }
 
+void CAdvMapInt::updateSpellbook(const CGHeroInstance *h)
+{
+	spellbook->block(!h);
+}
+
 int CAdvMapInt::getNextHeroIndex(int startIndex)
 {
 	if (LOCPLINT->wanderingHeroes.size() == 0)
@@ -966,7 +970,7 @@ void CAdvMapInt::show(SDL_Surface * to)
 		for(int i=0;i<4;i++)
 			blitAt(gems[i]->ourImages[LOCPLINT->playerID.getNum()].bitmap,ADVOPT.gemX[i],ADVOPT.gemY[i],to);
 	}
-	
+
 	infoBar.show(to);
 	statusbar.showAll(to);
 }
@@ -981,7 +985,7 @@ void CAdvMapInt::selectionChanged()
 void CAdvMapInt::centerOn(int3 on, bool fade /* = false */)
 {
 	bool switchedLevels = on.z != position.z;
-	
+
 	if (fade)
 	{
 		terrain.fadeFromCurrentView();
@@ -1262,6 +1266,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
 
 		updateSleepWake(nullptr);
 		updateMoveHero(nullptr);
+		updateSpellbook(nullptr);
 	}
 	else //hero selected
 	{
@@ -1275,6 +1280,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
 
 		updateSleepWake(hero);
 		updateMoveHero(hero);
+		updateSpellbook(hero);
 	}
 	townList.redraw();
 	heroList.redraw();
@@ -1531,12 +1537,16 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
 	}
 	else if(const CGHeroInstance * h = curHero())
 	{
-		const CGPathNode * pnode = LOCPLINT->cb->getPathsInfo(h)->getPathInfo(mapPos);
+		int3 mapPosCopy = mapPos;
+		const CGPathNode * pnode = LOCPLINT->cb->getPathsInfo(h)->getPathInfo(mapPosCopy);
+		assert(pnode);
+
 		int turns = pnode->turns;
 		vstd::amin(turns, 3);
 		switch(pnode->action)
 		{
 		case CGPathNode::NORMAL:
+		case CGPathNode::TELEPORT_NORMAL:
 			if(pnode->layer == EPathfindingLayer::LAND)
 				CCS->curh->changeGraphic(ECursor::ADVENTURE, 4 + turns*6);
 			else
@@ -1545,6 +1555,7 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
 
 		case CGPathNode::VISIT:
 		case CGPathNode::BLOCKING_VISIT:
+		case CGPathNode::TELEPORT_BLOCKING_VISIT:
 			if(objAtTile && objAtTile->ID == Obj::HERO)
 			{
 				if(selection == objAtTile)
@@ -1559,6 +1570,7 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
 			break;
 
 		case CGPathNode::BATTLE:
+		case CGPathNode::TELEPORT_BATTLE:
 			CCS->curh->changeGraphic(ECursor::ADVENTURE, 5 + turns*6);
 			break;
 
@@ -1708,9 +1720,9 @@ void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale /* = 0.4f */)
 			townList.activate();
 			heroList.activate();
 			infoBar.activate();
-			
+
 			worldViewOptions.clear();
-			
+
 			break;
 		case EAdvMapMode::WORLD_VIEW:
 			panelMain->deactivate();
@@ -1780,14 +1792,13 @@ CAdvMapInt::WorldViewOptions::WorldViewOptions()
 void CAdvMapInt::WorldViewOptions::clear()
 {
 	showAllTerrain = false;
-	
+
 	iconPositions.clear();
 }
 
 void CAdvMapInt::WorldViewOptions::adjustDrawingInfo(MapDrawingInfo& info)
 {
 	info.showAllTerrain = showAllTerrain;
-	
-	info.additionalIcons = &iconPositions;	
-}
 
+	info.additionalIcons = &iconPositions;
+}

+ 1 - 0
client/windows/CAdvmapInterface.h

@@ -235,6 +235,7 @@ public:
 	//button updates
 	void updateSleepWake(const CGHeroInstance *h);
 	void updateMoveHero(const CGHeroInstance *h, tribool hasPath = boost::logic::indeterminate);
+	void updateSpellbook(const CGHeroInstance *h);
 	void updateNextHero(const CGHeroInstance *h);
 
 	/// changes current adventure map mode; used to switch between default view and world view; scale is ignored if EAdvMapMode == NORMAL

+ 5 - 2
client/windows/CCastleInterface.cpp

@@ -230,7 +230,7 @@ std::string CBuildingRect::getSubtitle()//hover text for building
 		}
 		else
 		{
-            logGlobal->warnStream() << "Problem: dwelling with id " << bid << " offers no creatures!";
+			logGlobal->warnStream() << "Problem: dwelling with id " << bid << " offers no creatures!";
 			return "#ERROR#";
 		}
 	}
@@ -501,7 +501,10 @@ void CCastleBuildings::recreate()
 
 	if(vstd::contains(town->builtBuildings, BuildingID::SHIPYARD))
 	{
-		std::vector <const CGObjectInstance *> vobjs = LOCPLINT->cb->getVisitableObjs(town->bestLocation());
+		auto bayPos = town->bestLocation();
+		if(!bayPos.valid())
+			logGlobal->warnStream() << "Shipyard in non-coastal town!";
+		std::vector <const CGObjectInstance *> vobjs = LOCPLINT->cb->getVisitableObjs(bayPos, false);
 		//there is visitable obj at shipyard output tile and it's a boat or hero (on boat)
 		if(!vobjs.empty() && (vobjs.front()->ID == Obj::BOAT || vobjs.front()->ID == Obj::HERO))
 		{

+ 2 - 2
client/windows/CQuestLog.cpp

@@ -86,7 +86,7 @@ void CQuestMinimap::addQuestMarks (const QuestInfo * q)
 	if (level != tile.z)
 		setLevel(tile.z);
 
-	auto pic = make_shared<CQuestIcon>("VwSymbol.def", 3, x, y);
+	auto pic = std::make_shared<CQuestIcon>("VwSymbol.def", 3, x, y);
 
 	pic->moveBy (Point ( -pic->pos.w/2, -pic->pos.h/2));
 	pic->callback = std::bind (&CQuestMinimap::iconClicked, this);
@@ -179,7 +179,7 @@ void CQuestLog::recreateLabelList()
 			else
 				text.addReplacement(quests[i].obj->getObjectName()); //get name of the object
 		}
-		auto label = make_shared<CQuestLabel>(Rect(13, 195, 149,31), FONT_SMALL, TOPLEFT, Colors::WHITE, text.toString());
+		auto label = std::make_shared<CQuestLabel>(Rect(13, 195, 149,31), FONT_SMALL, TOPLEFT, Colors::WHITE, text.toString());
 		label->disable();
 
 		label->callback = std::bind(&CQuestLog::selectQuest, this, i, currentLabel);

+ 2 - 2
client/windows/CQuestLog.h

@@ -58,7 +58,7 @@ public:
 
 class CQuestMinimap : public CMinimap
 {
-	std::vector <shared_ptr<CQuestIcon>> icons;
+	std::vector <std::shared_ptr<CQuestIcon>> icons;
 
 	void clickLeft(tribool down, bool previousState) override{}; //minimap ignores clicking on its surface
 	void iconClicked();
@@ -86,7 +86,7 @@ class CQuestLog : public CWindowObject
 	CLabel * hideCompleteLabel;
 
 	const std::vector<QuestInfo> quests;
-	std::vector <shared_ptr<CQuestLabel>> labels;
+	std::vector <std::shared_ptr<CQuestLabel>> labels;
 	CTextBox * description;
 	CQuestMinimap * minimap;
 	CSlider * slider; //scrolls quests

+ 1 - 1
client/windows/CTradeWindow.cpp

@@ -861,7 +861,7 @@ void CMarketplaceWindow::selectionChanged(bool side)
 			if(itemsType[1] == RESOURCE)
 				newAmount = LOCPLINT->cb->getResourceAmount(static_cast<Res::ERes>(soldItemId));
 			else if(itemsType[1] ==  CREATURE)
-				newAmount = hero->getStackCount(SlotID(hLeft->serial)) - (hero->Slots().size() == 1  &&  hero->needsLastStack());
+				newAmount = hero->getStackCount(SlotID(hLeft->serial)) - (hero->stacksCount() == 1  &&  hero->needsLastStack());
 			else
 				assert(0);
 

+ 2 - 2
client/windows/GUIClasses.cpp

@@ -704,7 +704,7 @@ CTavernWindow::CTavernWindow(const CGObjectInstance *TavernObj):
 	oldSelected = -1;
 
 	new CLabel(200, 35, FONT_BIG, CENTER, Colors::YELLOW, CGI->generaltexth->jktexts[37]);
-	new CLabel(320, 328, FONT_SMALL, CENTER, Colors::WHITE, "2500");
+	new CLabel(320, 328, FONT_SMALL, CENTER, Colors::WHITE, boost::lexical_cast<std::string>(GameConstants::HERO_GOLD_COST));
 
 	auto rumorText = boost::str(boost::format(CGI->generaltexth->allTexts[216]) % LOCPLINT->cb->getTavernRumor(tavernObj));
 	new CTextBox(rumorText, Rect(32, 190, 330, 68), 0, FONT_SMALL, CENTER, Colors::WHITE);
@@ -714,7 +714,7 @@ CTavernWindow::CTavernWindow(const CGObjectInstance *TavernObj):
 	recruit = new CButton(Point(272, 355), "TPTAV01.DEF", CButton::tooltip(), std::bind(&CTavernWindow::recruitb, this), SDLK_RETURN);
 	thiefGuild = new CButton(Point(22, 428), "TPTAV02.DEF", CButton::tooltip(CGI->generaltexth->tavernInfo[5]), std::bind(&CTavernWindow::thievesguildb, this), SDLK_t);
 
-	if(LOCPLINT->cb->getResourceAmount(Res::GOLD) < 2500) //not enough gold
+	if(LOCPLINT->cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST) //not enough gold
 	{
 		recruit->addHoverText(CButton::NORMAL, CGI->generaltexth->tavernInfo[0]); //Cannot afford a Hero
 		recruit->block(true);

+ 1 - 1
lib/BattleAction.cpp

@@ -4,7 +4,7 @@
 #include "BattleState.h"
 
 /*
- * BattleAction.h, part of VCMI engine
+ * BattleAction.cpp, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *

+ 13 - 15
lib/BattleState.cpp

@@ -201,9 +201,7 @@ void BattleInfo::localInitStack(CStack * s)
 
 namespace CGH
 {
-	using namespace std;
-
-	static void readBattlePositions(const JsonNode &node, vector< vector<int> > & dest)
+	static void readBattlePositions(const JsonNode &node, std::vector< std::vector<int> > & dest)
 	{
 		for(const JsonNode &level : node.Vector())
 		{
@@ -375,7 +373,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp
 
 			try
 			{
-				auto obstPtr = make_shared<CObstacleInstance>();
+				auto obstPtr = std::make_shared<CObstacleInstance>();
 				obstPtr->obstacleType = CObstacleInstance::ABSOLUTE_OBSTACLE;
 				obstPtr->ID = obidgen.getSuchNumber(appropriateAbsoluteObstacle);
 				obstPtr->uniqueID = curB->obstacles.size();
@@ -424,7 +422,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp
 
 				RangeGenerator posgenerator(18, 168, ourRand);
 
-				auto obstPtr = make_shared<CObstacleInstance>();
+				auto obstPtr = std::make_shared<CObstacleInstance>();
 				obstPtr->ID = obid;
 				obstPtr->pos = posgenerator.getSuchNumber(validPosition);
 				obstPtr->uniqueID = curB->obstacles.size();
@@ -541,7 +539,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp
 		}
 
 		//moat
-		auto moat = make_shared<MoatObstacle>();
+		auto moat = std::make_shared<MoatObstacle>();
 		moat->ID = curB->town->subID;
 		moat->obstacleType = CObstacleInstance::MOAT;
 		moat->uniqueID = curB->obstacles.size();
@@ -586,19 +584,19 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp
 
 	case BFieldType::HOLY_GROUND:
 		{
-			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared<CreatureAlignmentLimiter>(EAlignment::GOOD)));
-			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared<CreatureAlignmentLimiter>(EAlignment::EVIL)));
+			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(std::make_shared<CreatureAlignmentLimiter>(EAlignment::GOOD)));
+			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(std::make_shared<CreatureAlignmentLimiter>(EAlignment::EVIL)));
 			break;
 		}
 	case BFieldType::CLOVER_FIELD:
 		{ //+2 luck bonus for neutral creatures
-			curB->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, +2, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared<CreatureAlignmentLimiter>(EAlignment::NEUTRAL)));
+			curB->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, +2, Bonus::TERRAIN_OVERLAY)->addLimiter(std::make_shared<CreatureAlignmentLimiter>(EAlignment::NEUTRAL)));
 			break;
 		}
 	case BFieldType::EVIL_FOG:
 		{
-			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared<CreatureAlignmentLimiter>(EAlignment::GOOD)));
-			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared<CreatureAlignmentLimiter>(EAlignment::EVIL)));
+			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(std::make_shared<CreatureAlignmentLimiter>(EAlignment::GOOD)));
+			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(std::make_shared<CreatureAlignmentLimiter>(EAlignment::EVIL)));
 			break;
 		}
 	case BFieldType::CURSED_GROUND:
@@ -614,7 +612,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp
 	//overlay premies given
 
 	//native terrain bonuses
-	auto nativeTerrain = make_shared<CreatureNativeTerrainLimiter>(curB->terrainType);
+	auto nativeTerrain = std::make_shared<CreatureNativeTerrainLimiter>(curB->terrainType);
 	curB->addNewBonus(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
 	curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
 	curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
@@ -703,13 +701,13 @@ int BattleInfo::getIdForNewStack() const
 	return 0;
 }
 
-shared_ptr<CObstacleInstance> BattleInfo::getObstacleOnTile(BattleHex tile) const
+std::shared_ptr<CObstacleInstance> BattleInfo::getObstacleOnTile(BattleHex tile) const
 {
 	for(auto &obs : obstacles)
 		if(vstd::contains(obs->getAffectedTiles(), tile))
 			return obs;
 
-	return shared_ptr<CObstacleInstance>();
+	return std::shared_ptr<CObstacleInstance>();
 }
 
 BattlefieldBI::BattlefieldBI BattleInfo::battlefieldTypeToBI(BFieldType bfieldType)
@@ -719,7 +717,7 @@ BattlefieldBI::BattlefieldBI BattleInfo::battlefieldTypeToBI(BFieldType bfieldTy
 		{BFieldType::CLOVER_FIELD, BattlefieldBI::CLOVER_FIELD},
 		{BFieldType::CURSED_GROUND, BattlefieldBI::CURSED_GROUND},
 		{BFieldType::EVIL_FOG, BattlefieldBI::EVIL_FOG},
-		{BFieldType::FAVOURABLE_WINDS, BattlefieldBI::NONE},
+		{BFieldType::FAVORABLE_WINDS, BattlefieldBI::NONE},
 		{BFieldType::FIERY_FIELDS, BattlefieldBI::FIERY_FIELDS},
 		{BFieldType::HOLY_GROUND, BattlefieldBI::HOLY_GROUND},
 		{BFieldType::LUCID_POOLS, BattlefieldBI::LUCID_POOLS},

+ 2 - 2
lib/BattleState.h

@@ -83,7 +83,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
 	const CGTownInstance * town; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege)
 	int3 tile; //for background and bonuses
 	std::vector<CStack*> stacks;
-	std::vector<shared_ptr<CObstacleInstance> > obstacles;
+	std::vector<std::shared_ptr<CObstacleInstance> > obstacles;
 	SiegeInfo si;
 
 	BFieldType battlefieldType; //like !!BA:B
@@ -124,7 +124,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
 	//std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = nullptr, bool forPassingBy = false) const; //returns vector of accessible tiles (taking into account the creature range)
 
 	//bool isObstacleVisibleForSide(const CObstacleInstance &obstacle, ui8 side) const;
-	shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
+	std::shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
 	std::set<BattleHex> getStoppers(bool whichSidePerspective) const;
 
 	ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg, CRandomGenerator & rand); //charge - number of hexes travelled before attack (for champion's jousting)

+ 5 - 4
lib/CArtHandler.cpp

@@ -545,7 +545,7 @@ ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags)
 	return pickRandomArtifact(rand, flags, [](ArtifactID){ return true;});
 }
 
-Bonus *createBonus(Bonus::BonusType type, int val, int subtype, Bonus::ValueType valType, shared_ptr<ILimiter> limiter = shared_ptr<ILimiter>(), int additionalInfo = 0)
+Bonus *createBonus(Bonus::BonusType type, int val, int subtype, Bonus::ValueType valType, std::shared_ptr<ILimiter> limiter = std::shared_ptr<ILimiter>(), int additionalInfo = 0)
 {
 	auto added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,-1,subtype);
 	added->additionalInfo = additionalInfo;
@@ -554,7 +554,7 @@ Bonus *createBonus(Bonus::BonusType type, int val, int subtype, Bonus::ValueType
 	return added;
 }
 
-Bonus *createBonus(Bonus::BonusType type, int val, int subtype, shared_ptr<IPropagator> propagator = shared_ptr<IPropagator>(), int additionalInfo = 0)
+Bonus *createBonus(Bonus::BonusType type, int val, int subtype, std::shared_ptr<IPropagator> propagator = std::shared_ptr<IPropagator>(), int additionalInfo = 0)
 {
 	auto added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,-1,subtype);
 	added->additionalInfo = additionalInfo;
@@ -563,12 +563,12 @@ Bonus *createBonus(Bonus::BonusType type, int val, int subtype, shared_ptr<IProp
 	return added;
 }
 
-void CArtHandler::giveArtBonus( ArtifactID aid, Bonus::BonusType type, int val, int subtype, Bonus::ValueType valType, shared_ptr<ILimiter> limiter, int additionalInfo)
+void CArtHandler::giveArtBonus( ArtifactID aid, Bonus::BonusType type, int val, int subtype, Bonus::ValueType valType, std::shared_ptr<ILimiter> limiter, int additionalInfo)
 {
 	giveArtBonus(aid, createBonus(type, val, subtype, valType, limiter, additionalInfo));
 }
 
-void CArtHandler::giveArtBonus(ArtifactID aid, Bonus::BonusType type, int val, int subtype, shared_ptr<IPropagator> propagator /*= nullptr*/, int additionalInfo)
+void CArtHandler::giveArtBonus(ArtifactID aid, Bonus::BonusType type, int val, int subtype, std::shared_ptr<IPropagator> propagator /*= nullptr*/, int additionalInfo)
 {
 	giveArtBonus(aid, createBonus(type, val, subtype, propagator, additionalInfo));
 }
@@ -737,6 +737,7 @@ void CArtHandler::afterLoadFinalization()
 			bonus->sid = art->id;
 		}
 	}
+	CBonusSystemNode::treeHasChanged();
 }
 
 CArtifactInstance::CArtifactInstance()

+ 2 - 2
lib/CArtHandler.h

@@ -258,8 +258,8 @@ private:
 	void loadComponents(CArtifact * art, const JsonNode & node);
 	void loadGrowingArt(CGrowingArtifact * art, const JsonNode & node);
 
-	void giveArtBonus(ArtifactID aid, Bonus::BonusType type, int val, int subtype = -1, Bonus::ValueType valType = Bonus::BASE_NUMBER, shared_ptr<ILimiter> limiter = shared_ptr<ILimiter>(), int additionalinfo = 0);
-	void giveArtBonus(ArtifactID aid, Bonus::BonusType type, int val, int subtype, shared_ptr<IPropagator> propagator, int additionalinfo = 0);
+	void giveArtBonus(ArtifactID aid, Bonus::BonusType type, int val, int subtype = -1, Bonus::ValueType valType = Bonus::BASE_NUMBER, std::shared_ptr<ILimiter> limiter = std::shared_ptr<ILimiter>(), int additionalinfo = 0);
+	void giveArtBonus(ArtifactID aid, Bonus::BonusType type, int val, int subtype, std::shared_ptr<IPropagator> propagator, int additionalinfo = 0);
 	void giveArtBonus(ArtifactID aid, Bonus *bonus);
 
 	void erasePickedArt(ArtifactID id);

+ 5 - 5
lib/CBattleCallback.cpp

@@ -130,9 +130,9 @@ BFieldType CBattleInfoEssentials::battleGetBattlefieldType() const
 	return getBattle()->battlefieldType;
 }
 
-std::vector<shared_ptr<const CObstacleInstance> > CBattleInfoEssentials::battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective /*= boost::none*/) const
+std::vector<std::shared_ptr<const CObstacleInstance> > CBattleInfoEssentials::battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective /*= boost::none*/) const
 {
-	std::vector<shared_ptr<const CObstacleInstance> > ret;
+	std::vector<std::shared_ptr<const CObstacleInstance> > ret;
 	RETURN_IF_NOT_BATTLE(ret);
 
 	if(!perspective)
@@ -1100,9 +1100,9 @@ std::pair<ui32, ui32> CBattleInfoCallback::battleEstimateDamage(const BattleAtta
 	return ret;
 }
 
-shared_ptr<const CObstacleInstance> CBattleInfoCallback::battleGetObstacleOnPos(BattleHex tile, bool onlyBlocking /*= true*/) const
+std::shared_ptr<const CObstacleInstance> CBattleInfoCallback::battleGetObstacleOnPos(BattleHex tile, bool onlyBlocking /*= true*/) const
 {
-	RETURN_IF_NOT_BATTLE(shared_ptr<const CObstacleInstance>());
+	RETURN_IF_NOT_BATTLE(std::shared_ptr<const CObstacleInstance>());
 
 	for(auto &obs : battleGetAllObstacles())
 	{
@@ -1113,7 +1113,7 @@ shared_ptr<const CObstacleInstance> CBattleInfoCallback::battleGetObstacleOnPos(
 		}
 	}
 
-	return shared_ptr<const CObstacleInstance>();
+	return std::shared_ptr<const CObstacleInstance>();
 }
 
 AccessibilityInfo CBattleInfoCallback::getAccesibility() const

+ 2 - 2
lib/CBattleCallback.h

@@ -170,7 +170,7 @@ public:
 
 	ETerrainType battleTerrainType() const;
 	BFieldType battleGetBattlefieldType() const;
-	std::vector<shared_ptr<const CObstacleInstance> > battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective = boost::none) const; //returns all obstacles on the battlefield
+	std::vector<std::shared_ptr<const CObstacleInstance> > battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective = boost::none) const; //returns all obstacles on the battlefield
     
     /** @brief Main method for getting battle stacks
      *
@@ -243,7 +243,7 @@ public:
 	//battle
 	boost::optional<int> battleIsFinished() const; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
 
-	shared_ptr<const CObstacleInstance> battleGetObstacleOnPos(BattleHex tile, bool onlyBlocking = true) const; //blocking obstacles makes tile inaccessible, others cause special effects (like Land Mines, Moat, Quicksands)
+	std::shared_ptr<const CObstacleInstance> battleGetObstacleOnPos(BattleHex tile, bool onlyBlocking = true) const; //blocking obstacles makes tile inaccessible, others cause special effects (like Land Mines, Moat, Quicksands)
 	const CStack * battleGetStackByPos(BattleHex pos, bool onlyAlive = true) const; //returns stack info by given pos
 	void battleGetStackQueue(std::vector<const CStack *> &out, const int howMany, const int turn = 0, int lastMoved = -1) const;
 	void battleGetStackCountOutsideHexes(bool *ac) const; // returns hexes which when in front of a stack cause us to move the amount box back

+ 1 - 1
lib/CConfigHandler.h

@@ -3,7 +3,7 @@
 #include "../lib/JsonNode.h"
 
 /*
- * CConfighandler.h, part of VCMI engine
+ * CConfigHandler.h, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *

+ 10 - 3
lib/CCreatureHandler.cpp

@@ -140,6 +140,7 @@ void CCreature::setId(CreatureID ID)
 		if(bonus->source == Bonus::CREATURE_ABILITY)
 			bonus->sid = ID;
 	}
+	CBonusSystemNode::treeHasChanged();
 }
 
 static void AddAbility(CCreature *cre, const JsonVector &ability_vec)
@@ -488,8 +489,14 @@ void CCreatureHandler::loadCrExpBon()
 		}
 		do //parse everything that's left
 		{
-			b.sid = parser.readNumber(); //id = this particular creature ID
-			loadStackExp(b, creatures[b.sid]->getBonusList(), parser); //add directly to CCreature Node
+			auto sid = parser.readNumber(); //id = this particular creature ID
+			b.sid = sid;
+			bl.clear();
+			loadStackExp(b, bl, parser);
+			for(Bonus * b : bl)
+			{
+				creatures[sid]->addNewBonus(b); //add directly to CCreature Node
+			}
 		}
 		while (parser.endLine());
 
@@ -753,7 +760,7 @@ void CCreatureHandler::loadStackExperience(CCreature * creature, const JsonNode
 			{
 				if (val.Bool() == true)
 				{
-					bonus->limiter = make_shared<RankRangeLimiter>(RankRangeLimiter(lowerLimit));
+					bonus->limiter = std::make_shared<RankRangeLimiter>(RankRangeLimiter(lowerLimit));
 					creature->addNewBonus (new Bonus(*bonus)); //bonuses must be unique objects
 					break; //TODO: allow bonuses to turn off?
 				}

+ 28 - 3
lib/CCreatureSet.cpp

@@ -225,14 +225,39 @@ ui64 CCreatureSet::getPower (SlotID slot) const
 	return getStack(slot).getPower();
 }
 
-std::string CCreatureSet::getRoughAmount (SlotID slot) const
+std::string CCreatureSet::getRoughAmount(SlotID slot, int mode) const
 {
+	/// Mode represent return string format
+	/// "Pack" - 0, "A pack of" - 1, "a pack of" - 2
 	int quantity = CCreature::getQuantityID(getStackCount(slot));
-	if (quantity)
-		return VLC->generaltexth->arraytxt[174 + 3*CCreature::getQuantityID(getStackCount(slot))];
+	if(quantity)
+		return VLC->generaltexth->arraytxt[(174 + mode) + 3*CCreature::getQuantityID(getStackCount(slot))];
 	return "";
 }
 
+std::string CCreatureSet::getArmyDescription() const
+{
+	std::string text;
+	std::vector<std::string> guards;
+	for(auto & elem : stacks)
+	{
+		auto str = boost::str(boost::format("%s %s") % getRoughAmount(elem.first, 2) % getCreature(elem.first)->namePl);
+		guards.push_back(str);
+	}
+	if(guards.size())
+	{
+		for(int i = 0; i < guards.size(); i++)
+		{
+			text += guards[i];
+			if(i + 2 < guards.size())
+				text += ", ";
+			else if(i + 2 == guards.size())
+				text += VLC->generaltexth->allTexts[237];
+		}
+	}
+	return text;
+}
+
 int CCreatureSet::stacksCount() const
 {
 	return stacks.size();

+ 2 - 1
lib/CCreatureSet.h

@@ -200,7 +200,8 @@ public:
 	virtual bool needsLastStack() const; //true if last stack cannot be taken
 	ui64 getArmyStrength() const; //sum of AI values of creatures
 	ui64 getPower (SlotID slot) const; //value of specific stack
-	std::string getRoughAmount (SlotID slot) const; //rough size of specific stack
+	std::string getRoughAmount(SlotID slot, int mode = 0) const; //rough size of specific stack
+	std::string getArmyDescription() const;
 	bool hasStackAtSlot(SlotID slot) const;
 
 	bool contains(const CStackInstance *stack) const;

+ 3 - 3
lib/CGameInfoCallback.cpp

@@ -475,7 +475,7 @@ const TerrainTile * CGameInfoCallback::getTile( int3 tile, bool verbose) const
 }
 
 //TODO: typedef?
-shared_ptr<boost::multi_array<TerrainTile*, 3>> CGameInfoCallback::getAllVisibleTiles() const
+std::shared_ptr<boost::multi_array<TerrainTile*, 3>> CGameInfoCallback::getAllVisibleTiles() const
 {
 	assert(player.is_initialized());
 	auto team = getPlayerTeam(player.get());
@@ -496,7 +496,7 @@ shared_ptr<boost::multi_array<TerrainTile*, 3>> CGameInfoCallback::getAllVisible
 				else
 					tileArray[x][y][z] = nullptr;
 			}
-	return make_shared<boost::multi_array<TerrainTile*, 3>>(tileArray);
+	return std::make_shared<boost::multi_array<TerrainTile*, 3>>(tileArray);
 }
 
 EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTownInstance *t, BuildingID ID )
@@ -577,7 +577,7 @@ EPlayerStatus::EStatus CGameInfoCallback::getPlayerStatus(PlayerColor player, bo
 std::string CGameInfoCallback::getTavernRumor(const CGObjectInstance * townOrTavern) const
 {
 	std::string text = "", extraText = "";
-	if(gs->rumor.type == RumorState::TYPE_NONE) // (version < 755 backward compatability
+	if(gs->rumor.type == RumorState::TYPE_NONE)
 		return text;
 
 	auto rumor = gs->rumor.last[gs->rumor.type];

+ 1 - 1
lib/CGameInfoCallback.h

@@ -91,7 +91,7 @@ public:
 	const CMapHeader * getMapHeader()const;
 	int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map
 	const TerrainTile * getTile(int3 tile, bool verbose = true) const;
-	shared_ptr<boost::multi_array<TerrainTile*, 3>> getAllVisibleTiles() const;
+	std::shared_ptr<boost::multi_array<TerrainTile*, 3>> getAllVisibleTiles() const;
 	bool isInTheMap(const int3 &pos) const;
 
 	//town

+ 10 - 10
lib/CGameInterface.cpp

@@ -24,19 +24,19 @@
 #ifdef VCMI_ANDROID
 // 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_GetNewAI(shared_ptr<CGlobalAI> &out);
+extern "C" DLL_EXPORT void VCAI_GetNewAI(std::shared_ptr<CGlobalAI> &out);
 
 extern "C" DLL_EXPORT void StupidAI_GetAiName(char* name);
-extern "C" DLL_EXPORT void StupidAI_GetNewBattleAI(shared_ptr<CGlobalAI> &out);
+extern "C" DLL_EXPORT void StupidAI_GetNewBattleAI(std::shared_ptr<CGlobalAI> &out);
 
 extern "C" DLL_EXPORT void BattleAI_GetAiName(char* name);
-extern "C" DLL_EXPORT void BattleAI_GetNewBattleAI(shared_ptr<CBattleGameInterface> &out);
+extern "C" DLL_EXPORT void BattleAI_GetNewBattleAI(std::shared_ptr<CBattleGameInterface> &out);
 #endif
 
 template<typename rett>
-shared_ptr<rett> createAny(const boost::filesystem::path& libpath, const std::string& methodName)
+std::shared_ptr<rett> createAny(const boost::filesystem::path& libpath, const std::string& methodName)
 {
-	typedef void(*TGetAIFun)(shared_ptr<rett>&); 
+	typedef void(*TGetAIFun)(std::shared_ptr<rett>&); 
 	typedef void(*TGetNameFun)(char*); 
 
 	char temp[150];
@@ -102,7 +102,7 @@ shared_ptr<rett> createAny(const boost::filesystem::path& libpath, const std::st
 	getName(temp);
     logGlobal->infoStream() << "Loaded " << temp;
 
-	shared_ptr<rett> ret;
+	std::shared_ptr<rett> ret;
 	getAI(ret);
 	if(!ret)
         logGlobal->errorStream() << "Cannot get AI!";
@@ -111,7 +111,7 @@ shared_ptr<rett> createAny(const boost::filesystem::path& libpath, const std::st
 }
 
 template<typename rett>
-shared_ptr<rett> createAnyAI(std::string dllname, const std::string& methodName)
+std::shared_ptr<rett> createAnyAI(std::string dllname, const std::string& methodName)
 {
 	logGlobal->infoStream() << "Opening " << dllname;
 	const boost::filesystem::path filePath =
@@ -121,17 +121,17 @@ shared_ptr<rett> createAnyAI(std::string dllname, const std::string& methodName)
 	return ret;
 }
 
-shared_ptr<CGlobalAI> CDynLibHandler::getNewAI(std::string dllname)
+std::shared_ptr<CGlobalAI> CDynLibHandler::getNewAI(std::string dllname)
 {
 	return createAnyAI<CGlobalAI>(dllname, "GetNewAI");
 }
 
-shared_ptr<CBattleGameInterface> CDynLibHandler::getNewBattleAI(std::string dllname )
+std::shared_ptr<CBattleGameInterface> CDynLibHandler::getNewBattleAI(std::string dllname )
 {
 	return createAnyAI<CBattleGameInterface>(dllname, "GetNewBattleAI");
 }
 
-shared_ptr<CScriptingModule> CDynLibHandler::getNewScriptingModule(std::string dllname)
+std::shared_ptr<CScriptingModule> CDynLibHandler::getNewScriptingModule(std::string dllname)
 {
 	return createAny<CScriptingModule>(dllname, "GetNewModule");
 }

+ 7 - 7
lib/CGameInterface.h

@@ -67,7 +67,7 @@ public:
 	std::string dllName;
 
 	virtual ~CBattleGameInterface() {};
-	virtual void init(shared_ptr<CBattleCallback> CB){};
+	virtual void init(std::shared_ptr<CBattleCallback> CB){};
 
 	//battle call-ins
 	virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
@@ -82,7 +82,7 @@ public:
 class DLL_LINKAGE CGameInterface : public CBattleGameInterface, public IGameEventsReceiver
 {
 public:
-	virtual void init(shared_ptr<CCallback> CB){};
+	virtual void init(std::shared_ptr<CCallback> CB){};
 	virtual void yourTurn(){}; //called AFTER playerStartsTurn(player)
 
 	//pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
@@ -105,9 +105,9 @@ public:
 class DLL_LINKAGE CDynLibHandler
 {
 public:
-	static shared_ptr<CGlobalAI> getNewAI(std::string dllname);
-	static shared_ptr<CBattleGameInterface> getNewBattleAI(std::string dllname);
-	static shared_ptr<CScriptingModule> getNewScriptingModule(std::string dllname);
+	static std::shared_ptr<CGlobalAI> getNewAI(std::string dllname);
+	static std::shared_ptr<CBattleGameInterface> getNewBattleAI(std::string dllname);
+	static std::shared_ptr<CScriptingModule> getNewScriptingModule(std::string dllname);
 };
 
 class DLL_LINKAGE CGlobalAI : public CGameInterface // AI class (to derivate)
@@ -123,8 +123,8 @@ class DLL_LINKAGE CAdventureAI : public CGlobalAI
 public:
 	CAdventureAI() {};
 
-	shared_ptr<CBattleGameInterface> battleAI;
-	shared_ptr<CBattleCallback> cbc;
+	std::shared_ptr<CBattleGameInterface> battleAI;
+	std::shared_ptr<CBattleCallback> cbc;
 
 	virtual std::string getBattleAIName() const = 0; //has to return name of the battle AI to be used
 

+ 4 - 4
lib/CGameState.cpp

@@ -675,8 +675,8 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
 	}
 	else
 	{
-		cur->setType(ran.first, ran.second);	
-	}	
+		cur->setType(ran.first, ran.second);
+	}
 }
 
 int CGameState::getDate(Date::EDateType mode) const
@@ -1939,7 +1939,7 @@ BFieldType CGameState::battleGetBattlefieldType(int3 tile)
 		case Obj::EVIL_FOG:
 			return BFieldType::EVIL_FOG;
 		case Obj::FAVORABLE_WINDS:
-			return BFieldType::FAVOURABLE_WINDS;
+			return BFieldType::FAVORABLE_WINDS;
 		case Obj::FIERY_FIELDS:
 			return BFieldType::FIERY_FIELDS;
 		case Obj::HOLY_GROUNDS:
@@ -3177,7 +3177,7 @@ DuelParameters DuelParameters::fromJSON(const std::string &fname)
 
 	for(const JsonNode &n : duelData["obstacles"].Vector())
 	{
-		auto oi = make_shared<CObstacleInstance>();
+		auto oi = std::make_shared<CObstacleInstance>();
 		if(n.getType() == JsonNode::DATA_VECTOR)
 		{
 			oi->ID = n.Vector()[0].Float();

+ 3 - 3
lib/CGameState.h

@@ -100,7 +100,7 @@ struct DLL_LINKAGE RumorState
 	ERumorType type;
 	std::map<ERumorType, std::pair<int, int>> last;
 
-	RumorState(){type = TYPE_NONE; last = {};};
+	RumorState(){type = TYPE_NONE;};
 	bool update(int id, int extra);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -149,7 +149,7 @@ struct DLL_EXPORT DuelParameters
 		}
 	} sides[2];
 
-	std::vector<shared_ptr<CObstacleInstance> > obstacles;
+	std::vector<std::shared_ptr<CObstacleInstance> > obstacles;
 
 	static DuelParameters fromJSON(const std::string &fname);
 
@@ -249,7 +249,7 @@ public:
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects & rand;
-		if(version >= 755)
+		if(version >= 755) //save format backward compatibility
 		{
 			h & rumor;
 		}

+ 70 - 18
lib/CPathfinder.cpp

@@ -150,22 +150,24 @@ void CPathfinder::calculatePaths()
 					continue;
 
 				destAction = getDestAction();
-				int cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, ct, dt, movement, hlp->getTurnInfo());
-				int remains = movement - cost;
-				if(destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK)
-				{
-					remains = hero->movementPointsAfterEmbark(movement, cost, destAction - 1, hlp->getTurnInfo());
-					cost = movement - remains;
-				}
-				int turnAtNextTile = turn;
+				int turnAtNextTile = turn, moveAtNextTile = movement;
+				int cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, ct, dt, moveAtNextTile, hlp->getTurnInfo());
+				int remains = moveAtNextTile - cost;
 				if(remains < 0)
 				{
 					//occurs rarely, when hero with low movepoints tries to leave the road
 					hlp->updateTurnInfo(++turnAtNextTile);
-					int moveAtNextTile = hlp->getMaxMovePoints(i);
+					moveAtNextTile = hlp->getMaxMovePoints(i);
 					cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, ct, dt, moveAtNextTile, hlp->getTurnInfo()); //cost must be updated, movement points changed :(
 					remains = moveAtNextTile - cost;
 				}
+				if(destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK)
+				{
+					/// FREE_SHIP_BOARDING bonus only remove additional penalty
+					/// land <-> sail transition still cost movement points as normal movement
+					remains = hero->movementPointsAfterEmbark(moveAtNextTile, cost, destAction - 1, hlp->getTurnInfo());
+					cost = moveAtNextTile - remains;
+				}
 
 				if(isBetterWay(remains, turnAtNextTile) &&
 					((cp->turns == turnAtNextTile && remains) || passOneTurnLimitCheck()))
@@ -189,14 +191,24 @@ void CPathfinder::calculatePaths()
 			dp = out.getNode(neighbour, cp->layer);
 			if(dp->locked)
 				continue;
+			/// TODO: We may consider use invisible exits on FoW border in future
+			/// Useful for AI when at least one tile around exit is visible and passable
+			/// Objects are usually visible on FoW border anyway so it's not cheating.
+			///
+			/// For now it's disabled as it's will cause crashes in movement code.
+			if(dp->accessible == CGPathNode::BLOCKED)
+				continue;
 
 			if(isBetterWay(movement, turn))
 			{
+				dtObj = gs->map->getTile(neighbour).topVisitableObj();
+
 				dp->moveRemains = movement;
 				dp->turns = turn;
 				dp->theNodeBefore = cp;
-				dp->action = CGPathNode::NORMAL;
-				pq.push(dp);
+				dp->action = getTeleportDestAction();
+				if(dp->action == CGPathNode::TELEPORT_NORMAL)
+					pq.push(dp);
 			}
 		}
 	} //queue loop
@@ -361,6 +373,16 @@ bool CPathfinder::isLayerTransitionPossible() const
 			return false;
 		}
 
+		break;
+
+	case ELayer::WATER:
+		if(dp->accessible != CGPathNode::ACCESSIBLE && dp->accessible != CGPathNode::VISITABLE)
+		{
+			/// Hero that walking on water can transit to accessible and visitable tiles
+			/// Though hero can't interact with blocking visit objects while standing on water
+			return false;
+		}
+
 		break;
 	}
 
@@ -443,7 +465,7 @@ bool CPathfinder::isMovementAfterDestPossible() const
 			/// Transit over whirlpools only allowed when hero protected
 			return true;
 		}
-		else if(dtObj->ID == Obj::GARRISON || dtObj->ID == Obj::GARRISON2)
+		else if(dtObj->ID == Obj::GARRISON || dtObj->ID == Obj::GARRISON2 || dtObj->ID == Obj::BORDER_GATE)
 		{
 			/// Transit via unguarded garrisons is always possible
 			return true;
@@ -507,18 +529,33 @@ CGPathNode::ENodeAction CPathfinder::getDestAction() const
 				else
 					action = CGPathNode::BLOCKING_VISIT;
 			}
-			else if(dtObj->ID == Obj::TOWN && objRel == PlayerRelations::ENEMIES)
+			else if(dtObj->ID == Obj::TOWN)
 			{
-				const CGTownInstance * townObj = dynamic_cast<const CGTownInstance *>(dtObj);
-				if(townObj->armedGarrison())
+				if(dtObj->passableFor(hero->tempOwner))
+					action = CGPathNode::VISIT;
+				else if(objRel == PlayerRelations::ENEMIES)
 					action = CGPathNode::BATTLE;
 			}
 			else if(dtObj->ID == Obj::GARRISON || dtObj->ID == Obj::GARRISON2)
 			{
-				const CGGarrison * garrisonObj = dynamic_cast<const CGGarrison *>(dtObj);
-				if((garrisonObj->stacksCount() && objRel == PlayerRelations::ENEMIES) || isDestinationGuarded(true))
+				if(dtObj->passableFor(hero->tempOwner))
+				{
+					if(isDestinationGuarded(true))
+						action = CGPathNode::BATTLE;
+				}
+				else if(objRel == PlayerRelations::ENEMIES)
 					action = CGPathNode::BATTLE;
 			}
+			else if(dtObj->ID == Obj::BORDER_GATE)
+			{
+				if(dtObj->passableFor(hero->tempOwner))
+				{
+					if(isDestinationGuarded(true))
+						action = CGPathNode::BATTLE;
+				}
+				else
+					action = CGPathNode::BLOCKING_VISIT;
+			}
 			else if(isDestinationGuardian())
 				action = CGPathNode::BATTLE;
 			else if(dtObj->blockVisit && !(options.useCastleGate && dtObj->ID == Obj::TOWN))
@@ -541,6 +578,21 @@ CGPathNode::ENodeAction CPathfinder::getDestAction() const
 	return action;
 }
 
+CGPathNode::ENodeAction CPathfinder::getTeleportDestAction() const
+{
+	CGPathNode::ENodeAction action = CGPathNode::TELEPORT_NORMAL;
+	if(isDestVisitableObj() && dtObj->ID == Obj::HERO)
+	{
+		auto objRel = getPlayerRelations(dtObj->tempOwner, hero->tempOwner);
+		if(objRel == PlayerRelations::ENEMIES)
+			action = CGPathNode::TELEPORT_BATTLE;
+		else
+			action = CGPathNode::TELEPORT_BLOCKING_VISIT;
+	}
+
+	return action;
+}
+
 bool CPathfinder::isSourceInitialPosition() const
 {
 	return cp->coord == out.hpos;
@@ -987,7 +1039,7 @@ int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 & sr
 	}
 	else if(dt->terType == ETerrainType::WATER)
 	{
-		if(h->boat && ct->hasFavourableWinds() && dt->hasFavourableWinds()) //Favourable Winds
+		if(h->boat && ct->hasFavorableWinds() && dt->hasFavorableWinds())
 			ret *= 0.666;
 		else if(!h->boat && ti->hasBonusOfType(Bonus::WATER_WALKING))
 		{

+ 7 - 3
lib/CPathfinder.h

@@ -36,7 +36,10 @@ struct DLL_LINKAGE CGPathNode
 		NORMAL,
 		BATTLE,
 		VISIT,
-		BLOCKING_VISIT
+		BLOCKING_VISIT,
+		TELEPORT_NORMAL,
+		TELEPORT_BLOCKING_VISIT,
+		TELEPORT_BATTLE
 	};
 
 	enum EAccessibility : ui8
@@ -159,7 +162,7 @@ private:
 	CPathsInfo & out;
 	const CGHeroInstance * hero;
 	const std::vector<std::vector<std::vector<ui8> > > &FoW;
-	unique_ptr<CPathfinderHelper> hlp;
+	std::unique_ptr<CPathfinderHelper> hlp;
 
 	enum EPatrolState {
 		PATROL_NONE = 0,
@@ -202,6 +205,7 @@ private:
 	bool isMovementToDestPossible() const;
 	bool isMovementAfterDestPossible() const;
 	CGPathNode::ENodeAction getDestAction() const;
+	CGPathNode::ENodeAction getTeleportDestAction() const;
 
 	bool isSourceInitialPosition() const;
 	bool isSourceVisitableObj() const;
@@ -240,7 +244,7 @@ struct DLL_LINKAGE TurnInfo
 
 		BonusCache(TBonusListPtr bonusList);
 	};
-	unique_ptr<BonusCache> bonusCache;
+	std::unique_ptr<BonusCache> bonusCache;
 
 	const CGHeroInstance * hero;
 	TBonusListPtr bonuses;

+ 1 - 1
lib/CStopWatch.h

@@ -11,7 +11,7 @@
 #endif
 
 /*
- * timeHandler.h, part of VCMI engine
+ * CStopWatch.h, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *

+ 37 - 40
lib/Connection.cpp

@@ -17,9 +17,6 @@
  *
  */
 
-using namespace boost;
-using namespace boost::asio::ip;
-
 extern template void registerTypes<CISer>(CISer & s);
 extern template void registerTypes<COSer>(COSer & s);
 extern template void registerTypes<CTypeList>(CTypeList & s);
@@ -70,13 +67,13 @@ void CConnection::init()
 }
 
 CConnection::CConnection(std::string host, std::string port, std::string Name)
-:iser(this), oser(this), io_service(new asio::io_service), name(Name) 
+:iser(this), oser(this), io_service(new boost::asio::io_service), name(Name)
 {
 	int i;
-	boost::system::error_code error = asio::error::host_not_found;
-	socket = new tcp::socket(*io_service);
-    tcp::resolver resolver(*io_service);
-    tcp::resolver::iterator end, pom, endpoint_iterator = resolver.resolve(tcp::resolver::query(host,port),error);
+	boost::system::error_code error = boost::asio::error::host_not_found;
+	socket = new boost::asio::ip::tcp::socket(*io_service);
+	boost::asio::ip::tcp::resolver resolver(*io_service);
+	boost::asio::ip::tcp::resolver::iterator end, pom, endpoint_iterator = resolver.resolve(boost::asio::ip::tcp::resolver::query(host,port),error);
 	if(error)
 	{
         logNetwork->errorStream() << "Problem with resolving: \n" << error;
@@ -121,7 +118,7 @@ connerror1:
 	else
         logNetwork->errorStream() << "No error info. ";
 	delete io_service;
-	//delete socket;	
+	//delete socket;
 	throw std::runtime_error("Can't establish connection :(");
 }
 CConnection::CConnection(TSocket * Socket, std::string Name )
@@ -132,14 +129,14 @@ CConnection::CConnection(TSocket * Socket, std::string Name )
 CConnection::CConnection(TAcceptor * acceptor, boost::asio::io_service *Io_service, std::string Name)
 : iser(this), oser(this), name(Name)//, send(this), rec(this)
 {
-	boost::system::error_code error = asio::error::host_not_found;
-	socket = new tcp::socket(*io_service);
+	boost::system::error_code error = boost::asio::error::host_not_found;
+	socket = new boost::asio::ip::tcp::socket(*io_service);
 	acceptor->accept(*socket,error);
 	if (error)
-	{ 
+	{
         logNetwork->errorStream() << "Error on accepting: " << error;
-		delete socket;	
-		throw std::runtime_error("Can't establish connection :("); 
+		delete socket;
+		throw std::runtime_error("Can't establish connection :(");
 	}
 	init();
 }
@@ -149,7 +146,7 @@ int CConnection::write(const void * data, unsigned size)
 	try
 	{
 		int ret;
-		ret = asio::write(*socket,asio::const_buffers_1(asio::const_buffer(data,size)));
+		ret = boost::asio::write(*socket,boost::asio::const_buffers_1(boost::asio::const_buffer(data,size)));
 		return ret;
 	}
 	catch(...)
@@ -164,7 +161,7 @@ int CConnection::read(void * data, unsigned size)
 	//LOG("Receiving " << size << " byte(s) of data" <<std::endl);
 	try
 	{
-		int ret = asio::read(*socket,asio::mutable_buffers_1(asio::mutable_buffer(data,size)));
+		int ret = boost::asio::read(*socket,boost::asio::mutable_buffers_1(boost::asio::mutable_buffer(data,size)));
 		return ret;
 	}
 	catch(...)
@@ -240,12 +237,12 @@ void CConnection::sendPackToServer(const CPack &pack, PlayerColor player, ui32 r
 
 void CConnection::disableStackSendingByID()
 {
-	CSerializer::sendStackInstanceByIds = false;	
+	CSerializer::sendStackInstanceByIds = false;
 }
 
 void CConnection::enableStackSendingByID()
 {
-	CSerializer::sendStackInstanceByIds = true;	
+	CSerializer::sendStackInstanceByIds = true;
 }
 
 void CConnection::disableSmartPointerSerialization()
@@ -285,7 +282,7 @@ void CConnection::enableSmartVectorMemberSerializatoin()
 	CSerializer::smartVectorMembersSerialization = true;
 }
 
-CSaveFile::CSaveFile( const std::string &fname ): serializer(this) 
+CSaveFile::CSaveFile( const std::string &fname ): serializer(this)
 {
 	registerTypes(serializer);
 	openNextFile(fname);
@@ -379,7 +376,7 @@ void CLoadFile::openNextFile(const boost::filesystem::path & fname, int minimalV
 		if(std::memcmp(buffer,"VCMI",4))
 			THROW_FORMAT("Error: not a VCMI file(%s)!", fName);
 
-		serializer >> serializer.fileVersion;	
+		serializer >> serializer.fileVersion;
 		if(serializer.fileVersion < minimalVersion)
 			THROW_FORMAT("Error: too old file format (%s)!", fName);
 
@@ -442,7 +439,7 @@ CTypeList::TypeInfoPtr CTypeList::registerType( const std::type_info *type )
 		return typeDescr;  //type found, return ptr to structure
 
 	//type not found - add it to the list and return given ID
-	auto newType = make_shared<TypeDescriptor>();
+	auto newType = std::make_shared<TypeDescriptor>();
 	newType->typeID = typeInfos.size() + 1;
 	newType->name = type->name();
 	typeInfos[type] = newType;
@@ -450,18 +447,19 @@ CTypeList::TypeInfoPtr CTypeList::registerType( const std::type_info *type )
 	return newType;
 }
 
-ui16 CTypeList::getTypeID( const std::type_info *type )
+ui16 CTypeList::getTypeID( const std::type_info *type, bool throws ) const
 {
-	auto i = typeInfos.find(type);
-	if(i != typeInfos.end())
-		return i->second->typeID;
-	else
+	auto descriptor = getTypeDescriptor(type, throws);
+	if (descriptor == nullptr)
+	{
 		return 0;
+	}
+	return descriptor->typeID;
 }
 
-std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, TypeInfoPtr to)
+std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, TypeInfoPtr to) const
 {
-	if(from == to)
+	if(!strcmp(from->name, to->name))
 		return std::vector<CTypeList::TypeInfoPtr>();
 
 	// Perform a simple BFS in the class hierarchy.
@@ -484,7 +482,7 @@ std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, Ty
 				}
 			}
 		}
-		
+
 		std::vector<TypeInfoPtr> ret;
 
 		if(!previous.count(from))
@@ -512,21 +510,21 @@ std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, Ty
 	return ret;
 }
 
-std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(const std::type_info *from, const std::type_info *to)
+std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(const std::type_info *from, const std::type_info *to) const
 {
 	//This additional if is needed because getTypeDescriptor might fail if type is not registered
 	// (and if casting is not needed, then registereing should no  be required)
-	if(*from == *to)
+	if(!strcmp(from->name(), to->name()))
 		return std::vector<CTypeList::TypeInfoPtr>();
 
 	return castSequence(getTypeDescriptor(from), getTypeDescriptor(to));
 }
 
-CTypeList::TypeInfoPtr CTypeList::getTypeDescriptor(const std::type_info *type, bool throws)
+CTypeList::TypeInfoPtr CTypeList::getTypeDescriptor(const std::type_info *type, bool throws) const
 {
 	auto i = typeInfos.find(type);
 	if(i != typeInfos.end())
-		return i->second; //type found, return ptr to structure	
+		return i->second; //type found, return ptr to structure
 
 	if(!throws)
 		return nullptr;
@@ -553,19 +551,19 @@ CSerializer::CSerializer()
 
 void CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib)
 {
-	registerVectoredType<CGObjectInstance, ObjectInstanceID>(&gs->map->objects, 
+	registerVectoredType<CGObjectInstance, ObjectInstanceID>(&gs->map->objects,
 		[](const CGObjectInstance &obj){ return obj.id; });
-	registerVectoredType<CHero, HeroTypeID>(&lib->heroh->heroes, 
+	registerVectoredType<CHero, HeroTypeID>(&lib->heroh->heroes,
 		[](const CHero &h){ return h.ID; });
 	registerVectoredType<CGHeroInstance, HeroTypeID>(&gs->map->allHeroes,
 		[](const CGHeroInstance &h){ return h.type->ID; });
-	registerVectoredType<CCreature, CreatureID>(&lib->creh->creatures, 
+	registerVectoredType<CCreature, CreatureID>(&lib->creh->creatures,
 		[](const CCreature &cre){ return cre.idNumber; });
 	registerVectoredType<CArtifact, ArtifactID>(&lib->arth->artifacts,
 		[](const CArtifact &art){ return art.id; });
-	registerVectoredType<CArtifactInstance, ArtifactInstanceID>(&gs->map->artInstances, 
+	registerVectoredType<CArtifactInstance, ArtifactInstanceID>(&gs->map->artInstances,
 		[](const CArtifactInstance &artInst){ return artInst.id; });
-	registerVectoredType<CQuest, si32>(&gs->map->quests, 
+	registerVectoredType<CQuest, si32>(&gs->map->quests,
 		[](const CQuest &q){ return q.qid; });
 
 	smartVectorMembersSerialization = true;
@@ -606,7 +604,7 @@ int CLoadIntegrityValidator::read( void * data, unsigned size )
 	return ret;
 }
 
-unique_ptr<CLoadFile> CLoadIntegrityValidator::decay()
+std::unique_ptr<CLoadFile> CLoadIntegrityValidator::decay()
 {
 	primaryFile->serializer.loadedPointers = this->serializer.loadedPointers;
 	primaryFile->serializer.loadedPointersTypes = this->serializer.loadedPointersTypes;
@@ -646,4 +644,3 @@ CMemorySerializer::CMemorySerializer(): iser(this), oser(this)
 	registerTypes(iser);
 	registerTypes(oser);
 }
-

+ 118 - 110
lib/Connection.h

@@ -81,10 +81,14 @@ enum SerializationLvl
 
 struct TypeComparer
 {
-	bool operator()(const std::type_info *a, const std::type_info *b) const
-	{
-		return a->before(*b);
-	}
+    bool operator()(const std::type_info *a, const std::type_info *b) const
+    {
+    #ifndef __APPLE__
+      return a->before(*b);
+    #else
+      return strcmp(a->name(), b->name()) < 0;
+    #endif
+    }
 };
 
 struct IPointerCaster
@@ -102,6 +106,11 @@ struct PointerCaster : IPointerCaster
 	{
 		From * from = (From*)boost::any_cast<void*>(ptr);
 		To * ret = dynamic_cast<To*>(from);
+		if (ret == nullptr)
+		{
+			// Last resort when RTTI goes mad
+			ret = static_cast<To*>(from);
+		}
 		return (void*)ret;
 	}
 
@@ -113,6 +122,11 @@ struct PointerCaster : IPointerCaster
 		{
 			auto from = boost::any_cast<SmartPt>(ptr);
 			auto ret = std::dynamic_pointer_cast<To>(from);
+			if (!ret)
+			{
+				// Last resort when RTTI goes mad
+				ret = std::static_pointer_cast<To>(from);
+			}
 			return ret;
 		}
 		catch(std::exception &e)
@@ -136,7 +150,7 @@ struct PointerCaster : IPointerCaster
 // 	}
 };
 
-class DLL_LINKAGE CTypeList
+class DLL_LINKAGE CTypeList: public boost::noncopyable
 {
 public:
 	struct TypeDescriptor;
@@ -147,33 +161,53 @@ public:
 		const char *name;
 		std::vector<TypeInfoPtr> children, parents;
 	};
+	typedef boost::shared_mutex TMutex;
+	typedef boost::unique_lock<TMutex> TUniqueLock;
+	typedef boost::shared_lock<TMutex> TSharedLock;
 private:
+	mutable TMutex mx;
 
 	std::map<const std::type_info *, TypeInfoPtr, TypeComparer> typeInfos;
 	std::map<std::pair<TypeInfoPtr, TypeInfoPtr>, std::unique_ptr<const IPointerCaster>> casters; //for each pair <Base, Der> we provide a caster (each registered relations creates a single entry here)
 
-	CTypeList(CTypeList &)
-	{
-		// This type is non-copyable.
-		// Unfortunately on Windows it is required for DLL_EXPORT-ed type to provide copy c-tor, so we can't =delete it.
-		assert(0);
-	}
-	CTypeList &operator=(CTypeList &)
+	/// Returns sequence of types starting from "from" and ending on "to". Every next type is derived from the previous.
+	/// Throws if there is no link registered.
+	std::vector<TypeInfoPtr> castSequence(TypeInfoPtr from, TypeInfoPtr to) const;
+	std::vector<TypeInfoPtr> castSequence(const std::type_info *from, const std::type_info *to) const;
+
+
+	template<boost::any(IPointerCaster::*CastingFunction)(const boost::any &) const>
+	boost::any castHelper(boost::any inputPtr, const std::type_info *fromArg, const std::type_info *toArg) const
 	{
-		// As above.
-		assert(0);
-		return *this;
+		TSharedLock lock(mx);
+		auto typesSequence = castSequence(fromArg, toArg);
+
+		boost::any ptr = inputPtr;
+		for(int i = 0; i < static_cast<int>(typesSequence.size()) - 1; i++)
+		{
+			auto &from = typesSequence[i];
+			auto &to = typesSequence[i + 1];
+			auto castingPair = std::make_pair(from, to);
+			if(!casters.count(castingPair))
+				THROW_FORMAT("Cannot find caster for conversion %s -> %s which is needed to cast %s -> %s", from->name % to->name % fromArg->name() % toArg->name());
+
+			auto &caster = casters.at(castingPair);
+			ptr = (*caster.*CastingFunction)(ptr); //Why does std::unique_ptr not have operator->* ..?
+		}
+
+		return ptr;
 	}
-public:
 
-	CTypeList();
+	TypeInfoPtr getTypeDescriptor(const std::type_info *type, bool throws = true) const; //if not throws, failure returns nullptr
 
 	TypeInfoPtr registerType(const std::type_info *type);
-
+public:
+	CTypeList();
 
 	template <typename Base, typename Derived>
 	void registerType(const Base * b = nullptr, const Derived * d = nullptr)
 	{
+		TUniqueLock lock(mx);
 		static_assert(std::is_base_of<Base, Derived>::value, "First registerType template parameter needs to ba a base class of the second one.");
 		static_assert(std::has_virtual_destructor<Base>::value, "Base class needs to have a virtual destructor.");
 		static_assert(!std::is_same<Base, Derived>::value, "Parameters of registerTypes should be two diffrenet types.");
@@ -187,77 +221,52 @@ public:
 		casters[std::make_pair(dti, bti)] = make_unique<const PointerCaster<Derived, Base>>();
 	}
 
-	ui16 getTypeID(const std::type_info *type);
-	TypeInfoPtr getTypeDescriptor(const std::type_info *type, bool throws = true); //if not throws, failure returns nullptr
+	ui16 getTypeID(const std::type_info *type, bool throws = false) const;
 
 	template <typename T>
-	ui16 getTypeID(const T * t = nullptr)
+	ui16 getTypeID(const T * t = nullptr, bool throws = false) const
 	{
-		return getTypeID(getTypeInfo(t));
-	}
-
-
-	// Returns sequence of types starting from "from" and ending on "to". Every next type is derived from the previous.
-	// Throws if there is no link registered.
-	std::vector<TypeInfoPtr> castSequence(TypeInfoPtr from, TypeInfoPtr to);
-	std::vector<TypeInfoPtr> castSequence(const std::type_info *from, const std::type_info *to);
-
-	template<boost::any(IPointerCaster::*CastingFunction)(const boost::any &) const>
-	boost::any castHelper(boost::any inputPtr, const std::type_info *fromArg, const std::type_info *toArg)
-	{
-		auto typesSequence = castSequence(fromArg, toArg);
-
-		boost::any ptr = inputPtr;
-		for(int i = 0; i < (int)typesSequence.size() - 1; i++)
-		{
-			auto &from = typesSequence[i];
-			auto &to = typesSequence[i + 1];
-			auto castingPair = std::make_pair(from, to);
-			if(!casters.count(castingPair))
-				THROW_FORMAT("Cannot find caster for conversion %s -> %s which is needed to cast %s -> %s", from->name % to->name % fromArg->name() % toArg->name());
-
-			auto &caster = casters.at(castingPair);
-			ptr = (*caster.*CastingFunction)(ptr); //Why does unique_ptr does not have operator->* ..?
-		}
-
-		return ptr;
+		return getTypeID(getTypeInfo(t), throws);
 	}
 
 	template<typename TInput>
-	void *castToMostDerived(const TInput *inputPtr)
+	void * castToMostDerived(const TInput * inputPtr) const
 	{
 		auto &baseType = typeid(typename std::remove_cv<TInput>::type);
 		auto derivedType = getTypeInfo(inputPtr);
 
-		if(baseType == *derivedType)
-			return (void*)inputPtr;
+		if (!strcmp(baseType.name(), derivedType->name()))
+		{
+			return const_cast<void*>(reinterpret_cast<const void*>(inputPtr));
+		}
 
-		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>((void*)inputPtr, &baseType, derivedType));
+		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>(
+			const_cast<void*>(reinterpret_cast<const void*>(inputPtr)), &baseType,
+			derivedType));
 	}
 
 	template<typename TInput>
-	boost::any castSharedToMostDerived(const std::shared_ptr<TInput> inputPtr)
+	boost::any castSharedToMostDerived(const std::shared_ptr<TInput> inputPtr) const
 	{
 		auto &baseType = typeid(typename std::remove_cv<TInput>::type);
 		auto derivedType = getTypeInfo(inputPtr.get());
 
-		if(baseType == *derivedType)
+		if (!strcmp(baseType.name(), derivedType->name()))
 			return inputPtr;
 
 		return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, &baseType, derivedType);
 	}
 
-	void* castRaw(void *inputPtr, const std::type_info *from, const std::type_info *to)
+	void * castRaw(void *inputPtr, const std::type_info *from, const std::type_info *to) const
 	{
 		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>(inputPtr, from, to));
 	}
-	boost::any castShared(boost::any inputPtr, const std::type_info *from, const std::type_info *to)
+	boost::any castShared(boost::any inputPtr, const std::type_info *from, const std::type_info *to) const
 	{
 		return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, from, to);
 	}
 
-
-	template <typename T> const std::type_info * getTypeInfo(const T * t = nullptr)
+	template <typename T> const std::type_info * getTypeInfo(const T * t = nullptr) const
 	{
 		if(t)
 			return &typeid(*t);
@@ -444,13 +453,13 @@ public:
 	virtual int write(const void * data, unsigned size) = 0;
 };
 
-class DLL_LINKAGE CSaverBase 
+class DLL_LINKAGE CSaverBase
 {
 protected:
 	IBinaryWriter * writer;
 public:
 	CSaverBase(IBinaryWriter * w): writer(w){};
-	
+
 	inline int write(const void * data, unsigned size)
 	{
 		return writer->write(data, size);
@@ -586,15 +595,15 @@ struct LoadIfStackInstance<Ser, CStackInstance *>
 class DLL_LINKAGE COSer : public CSaverBase
 {
 public:
-	
+
 	struct SaveBoolean
 	{
 		static void invoke(COSer &s, const bool &data)
 		{
 			s.saveBoolean(data);
 		}
-	};	
-	
+	};
+
 	struct SaveBooleanVector
 	{
 		static void invoke(COSer &s, const std::vector<bool> &data)
@@ -629,7 +638,7 @@ public:
 			s.saveEnum(data);
 		}
 	};
-		
+
 	template<typename T>
 	struct SavePointer
 	{
@@ -638,7 +647,7 @@ public:
 			s.savePointer(data);
 		}
 	};
-	
+
 	template<typename T>
 	struct SaveArray
 	{
@@ -655,9 +664,9 @@ public:
 		{
 			throw std::runtime_error("Wrong save serialization call!");
 		}
-	};	
-	
-	template <typename T> 
+	};
+
+	template <typename T>
 	class CPointerSaver : public CBasicPointerSaver
 	{
 	public:
@@ -665,12 +674,11 @@ public:
 		{
 			COSer &s = static_cast<COSer&>(ar);
 			const T *ptr = static_cast<const T*>(data);
-
 			//T is most derived known type, it's time to call actual serialize
-			const_cast<T&>(*ptr).serialize(s,version);
+			const_cast<T*>(ptr)->serialize(s,version);
 		}
-	};	
-			
+	};
+
 	bool saving;
 	std::map<ui16,CBasicPointerSaver*> savers; // typeID => CPointerSaver<serializer,type>
 
@@ -841,13 +849,13 @@ public:
 		const_cast<T&>(data).serialize(*this,version);
 	}
 	template <typename T>
-	void saveSerializable(const shared_ptr<T> &data)
+	void saveSerializable(const std::shared_ptr<T> &data)
 	{
 		T *internalPtr = data.get();
 		*this << internalPtr;
 	}
 	template <typename T>
-	void saveSerializable(const unique_ptr<T> &data)
+	void saveSerializable(const std::unique_ptr<T> &data)
 	{
 		T *internalPtr = data.get();
 		*this << internalPtr;
@@ -964,13 +972,13 @@ public:
 	virtual int read(void * data, unsigned size) = 0;
 };
 
-class DLL_LINKAGE CLoaderBase 
+class DLL_LINKAGE CLoaderBase
 {
 protected:
 	IBinaryReader * reader;
 public:
 	CLoaderBase(IBinaryReader * r): reader(r){};
-	
+
 	inline int read(void * data, unsigned size)
 	{
 		return reader->read(data, size);
@@ -1015,15 +1023,15 @@ public:
 			s.loadBoolean(data);
 		}
 	};
-	
+
 	struct LoadBooleanVector
 	{
 		static void invoke(CISer &s, std::vector<bool> &data)
 		{
 			s.loadBooleanVector(data);
 		}
-	};	
-	
+	};
+
 	template<typename T>
 	struct LoadEnum
 	{
@@ -1040,7 +1048,7 @@ public:
 		{
 			s.loadPrimitive(data);
 		}
-	};	
+	};
 
 	template<typename T>
 	struct LoadPointer
@@ -1049,8 +1057,8 @@ public:
 		{
 			s.loadPointer(data);
 		}
-	};	
-	
+	};
+
 	template<typename T>
 	struct LoadArray
 	{
@@ -1076,8 +1084,8 @@ public:
 		{
 			throw std::runtime_error("Wrong load serialization call!");
 		}
-	};	
-	
+	};
+
 	template <typename T> class CPointerLoader : public CBasicPointerLoader
 	{
 	public:
@@ -1094,8 +1102,8 @@ public:
 			ptr->serialize(s,version);
 			return &typeid(T);
 		}
-	};		
-	
+	};
+
 	bool saving;
 	std::map<ui16,CBasicPointerLoader*> loaders; // typeID => CPointerSaver<serializer,type>
 	si32 fileVersion;
@@ -1324,7 +1332,7 @@ public:
 
 
 	template <typename T>
-	void loadSerializable(shared_ptr<T> &data)
+	void loadSerializable(std::shared_ptr<T> &data)
 	{
 		typedef typename boost::remove_const<T>::type NonConstT;
 		NonConstT *internalPtr;
@@ -1345,7 +1353,7 @@ public:
 					auto typeWeNeedToReturn = typeList.getTypeInfo<T>();
 					if(*actualType == *typeWeNeedToReturn)
 					{
-						// No casting needed, just unpack already stored shared_ptr and return it
+						// No casting needed, just unpack already stored std::shared_ptr and return it
 						data = boost::any_cast<std::shared_ptr<T>>(itr->second);
 					}
 					else
@@ -1375,7 +1383,7 @@ public:
 			data.reset();
 	}
 	template <typename T>
-	void loadSerializable(unique_ptr<T> &data)
+	void loadSerializable(std::unique_ptr<T> &data)
 	{
 		T *internalPtr;
 		*this >> internalPtr;
@@ -1539,11 +1547,11 @@ class DLL_LINKAGE CSaveFile
 	:public IBinaryWriter
 {
 public:
-	
+
 	COSer serializer;
-	
+
 	std::string fName;
-	unique_ptr<std::ofstream> sfile;
+	std::unique_ptr<std::ofstream> sfile;
 
 	CSaveFile(const std::string &fname); //throws!
 	~CSaveFile();
@@ -1554,13 +1562,13 @@ public:
     void reportState(CLogger * out) override;
 
 	void putMagicBytes(const std::string &text);
-	
+
 	template<class T>
 	CSaveFile & operator<<(const T &t)
 	{
 		serializer << t;
 		return * this;
-	}		
+	}
 };
 
 class DLL_LINKAGE CLoadFile
@@ -1568,9 +1576,9 @@ class DLL_LINKAGE CLoadFile
 {
 public:
 	CISer serializer;
-		
+
 	std::string fName;
-	unique_ptr<boost::filesystem::ifstream> sfile;
+	std::unique_ptr<boost::filesystem::ifstream> sfile;
 
 	CLoadFile(const boost::filesystem::path & fname, int minimalVersion = version); //throws!
 	~CLoadFile();
@@ -1581,21 +1589,21 @@ public:
     void reportState(CLogger * out) override;
 
 	void checkMagicBytes(const std::string & text);
-	
+
 	template<class T>
 	CLoadFile & operator>>(T &t)
 	{
 		serializer >> t;
 		return * this;
-	}		
+	}
 };
 
-class DLL_LINKAGE CLoadIntegrityValidator 
+class DLL_LINKAGE CLoadIntegrityValidator
 	: public IBinaryReader
 {
 public:
-	CISer serializer;	
-	unique_ptr<CLoadFile> primaryFile, controlFile;
+	CISer serializer;
+	std::unique_ptr<CLoadFile> primaryFile, controlFile;
 	bool foundDesync;
 
 	CLoadIntegrityValidator(const std::string &primaryFileName, const std::string &controlFileName, int minimalVersion = version); //throws!
@@ -1603,7 +1611,7 @@ public:
 	int read( void * data, unsigned size) override; //throws!
 	void checkMagicBytes(const std::string &text);
 
-	unique_ptr<CLoadFile> decay(); //returns primary file. CLoadIntegrityValidator stops being usable anymore
+	std::unique_ptr<CLoadFile> decay(); //returns primary file. CLoadIntegrityValidator stops being usable anymore
 };
 
 typedef boost::asio::basic_stream_socket < boost::asio::ip::tcp , boost::asio::stream_socket_service<boost::asio::ip::tcp>  > TSocket;
@@ -1620,7 +1628,7 @@ class DLL_LINKAGE CConnection
 public:
 	CISer iser;
 	COSer oser;
-	
+
 	boost::mutex *rmx, *wmx; // read/write mutexes
 	TSocket * socket;
 	bool logging;
@@ -1658,14 +1666,14 @@ public:
 
 	void prepareForSendingHeroes(); //disables sending vectorised, enables smart pointer serialization, clears saved/loaded ptr cache
 	void enterPregameConnectionMode();
-	
+
 	template<class T>
 	CConnection & operator>>(T &t)
 	{
 		iser >> t;
 		return * this;
-	}	
-	
+	}
+
 	template<class T>
 	CConnection & operator<<(const T &t)
 	{
@@ -1687,19 +1695,19 @@ class DLL_LINKAGE CMemorySerializer
 public:
 	CISer iser;
 	COSer oser;
-		
+
 	int read(void * data, unsigned size) override; //throws!
 	int write(const void * data, unsigned size) override;
 
 	CMemorySerializer();
 
 	template <typename T>
-	static unique_ptr<T> deepCopy(const T &data)
+	static std::unique_ptr<T> deepCopy(const T &data)
 	{
 		CMemorySerializer mem;
 		mem.oser << &data;
 
-		unique_ptr<T> ret;
+		std::unique_ptr<T> ret;
 		mem.iser >> ret;
 		return ret;
 	}

+ 3 - 2
lib/GameConstants.h

@@ -33,6 +33,7 @@ namespace GameConstants
 	const int SPELL_SCHOOL_LEVELS = 4;
 	const int CRE_LEVELS = 10; // number of creature experience levels
 
+	const int HERO_GOLD_COST = 2500;
 	const int SPELLBOOK_GOLD_COST = 500;
 	const int BATTLE_PENALTY_DISTANCE = 10; //if the distance is > than this, then shooting stack has distance penalty
 	const int ARMY_SIZE = 7;
@@ -837,10 +838,10 @@ public:
 	//   1. sand/shore   2. sand/mesas   3. dirt/birches   4. dirt/hills   5. dirt/pines   6. grass/hills   7. grass/pines
 	//8. lava   9. magic plains   10. snow/mountains   11. snow/trees   12. subterranean   13. swamp/trees   14. fiery fields
 	//15. rock lands   16. magic clouds   17. lucid pools   18. holy ground   19. clover field   20. evil fog
-	//21. "favourable winds" text on magic plains background   22. cursed ground   23. rough   24. ship to ship   25. ship
+	//21. "favorable winds" text on magic plains background   22. cursed ground   23. rough   24. ship to ship   25. ship
 	enum EBFieldType {NONE = -1, NONE2, SAND_SHORE, SAND_MESAS, DIRT_BIRCHES, DIRT_HILLS, DIRT_PINES, GRASS_HILLS,
 		GRASS_PINES, LAVA, MAGIC_PLAINS, SNOW_MOUNTAINS, SNOW_TREES, SUBTERRANEAN, SWAMP_TREES, FIERY_FIELDS,
-		ROCKLANDS, MAGIC_CLOUDS, LUCID_POOLS, HOLY_GROUND, CLOVER_FIELD, EVIL_FOG, FAVOURABLE_WINDS, CURSED_GROUND,
+		ROCKLANDS, MAGIC_CLOUDS, LUCID_POOLS, HOLY_GROUND, CLOVER_FIELD, EVIL_FOG, FAVORABLE_WINDS, CURSED_GROUND,
 		ROUGH, SHIP_TO_SHIP, SHIP
 	};
 

+ 13 - 18
lib/HeroBonus.cpp

@@ -64,19 +64,19 @@ const std::map<std::string, Bonus::LimitEffect> bonusLimitEffect =
 
 const std::map<std::string, TLimiterPtr> bonusLimiterMap =
 {
-	{"SHOOTER_ONLY", make_shared<HasAnotherBonusLimiter>(Bonus::SHOOTER)},
-	{"DRAGON_NATURE", make_shared<HasAnotherBonusLimiter>(Bonus::DRAGON_NATURE)},
-	{"IS_UNDEAD", make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD)}
+	{"SHOOTER_ONLY", std::make_shared<HasAnotherBonusLimiter>(Bonus::SHOOTER)},
+	{"DRAGON_NATURE", std::make_shared<HasAnotherBonusLimiter>(Bonus::DRAGON_NATURE)},
+	{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD)}
 };
 
 const std::map<std::string, TPropagatorPtr> bonusPropagatorMap =
 {
-	{"BATTLE_WIDE", make_shared<CPropagatorNodeType>(CBonusSystemNode::BATTLE)},
-	{"VISITED_TOWN_AND_VISITOR", make_shared<CPropagatorNodeType>(CBonusSystemNode::TOWN_AND_VISITOR)},
-	{"PLAYER_PROPAGATOR", make_shared<CPropagatorNodeType>(CBonusSystemNode::PLAYER)},
-	{"HERO", make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO)},
-	{"TEAM_PROPAGATOR", make_shared<CPropagatorNodeType>(CBonusSystemNode::TEAM)}, //untested
-	{"GLOBAL_EFFECT", make_shared<CPropagatorNodeType>(CBonusSystemNode::GLOBAL_EFFECTS)}
+	{"BATTLE_WIDE", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::BATTLE)},
+	{"VISITED_TOWN_AND_VISITOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::TOWN_AND_VISITOR)},
+	{"PLAYER_PROPAGATOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::PLAYER)},
+	{"HERO", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO)},
+	{"TEAM_PROPAGATOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::TEAM)}, //untested
+	{"GLOBAL_EFFECT", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::GLOBAL_EFFECTS)}
 }; //untested
 
 
@@ -651,7 +651,7 @@ const TBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, c
 
 		//We still don't have the bonuses (didn't returned them from cache)
 		//Perform bonus selection
-		auto ret = make_shared<BonusList>();
+		auto ret = std::make_shared<BonusList>();
 		cachedBonuses.getBonuses(*ret, selector, limit);
 
 		// Save the results in the cache
@@ -668,7 +668,7 @@ const TBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, c
 
 const TBonusListPtr CBonusSystemNode::getAllBonusesWithoutCaching(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= nullptr*/) const
 {
-	auto ret = make_shared<BonusList>();
+	auto ret = std::make_shared<BonusList>();
 
 	// Get bonus results without caching enabled.
 	BonusList beforeLimiting, afterLimiting;
@@ -995,11 +995,6 @@ CBonusSystemNode::ENodeTypes CBonusSystemNode::getNodeType() const
 	return nodeType;
 }
 
-BonusList& CBonusSystemNode::getBonusList()
-{
-	return bonuses;
-}
-
 const BonusList& CBonusSystemNode::getBonusList() const
 {
 	return bonuses;
@@ -1072,7 +1067,7 @@ void CBonusSystemNode::limitBonuses(const BonusList &allBonuses, BonusList &out)
 
 TBonusListPtr CBonusSystemNode::limitBonuses(const BonusList &allBonuses) const
 {
-	auto ret = make_shared<BonusList>();
+	auto ret = std::make_shared<BonusList>();
 	limitBonuses(allBonuses, *ret);
 	return ret;
 }
@@ -1323,7 +1318,7 @@ Bonus * Bonus::addLimiter(TLimiterPtr Limiter)
 		if(!limiterList)
 		{
 			//Create a new limiter list with old limiter and the new one will be pushed later
-			limiterList = make_shared<LimiterList>();
+			limiterList = std::make_shared<LimiterList>();
 			limiterList->add(limiter);
 			limiter = limiterList;
 		}

+ 3 - 4
lib/HeroBonus.h

@@ -20,9 +20,9 @@ class ILimiter;
 class IPropagator;
 class BonusList;
 
-typedef shared_ptr<BonusList> TBonusListPtr;
-typedef shared_ptr<ILimiter> TLimiterPtr;
-typedef shared_ptr<IPropagator> TPropagatorPtr;
+typedef std::shared_ptr<BonusList> TBonusListPtr;
+typedef std::shared_ptr<ILimiter> TLimiterPtr;
+typedef std::shared_ptr<IPropagator> TPropagatorPtr;
 typedef std::set<CBonusSystemNode*> TNodes;
 typedef std::set<const CBonusSystemNode*> TCNodes;
 typedef std::vector<CBonusSystemNode *> TNodesVector;
@@ -694,7 +694,6 @@ public:
 	void exportBonus(Bonus * b);
 	void exportBonuses();
 
-	BonusList &getBonusList();
 	const BonusList &getBonusList() const;
 	BonusList &getExportedBonusList();
 	CBonusSystemNode::ENodeTypes getNodeType() const;

+ 3 - 3
lib/JsonNode.cpp

@@ -483,10 +483,10 @@ Bonus * JsonUtils::parseBonus (const JsonNode &ability)
 					break;
 				case JsonNode::DATA_STRUCT: //customizable limiters
 					{
-						shared_ptr<ILimiter> l;
+						std::shared_ptr<ILimiter> l;
 						if (limiter["type"].String() == "CREATURE_TYPE_LIMITER")
 						{
-							shared_ptr<CCreatureTypeLimiter> l2 = make_shared<CCreatureTypeLimiter>(); //TODO: How the hell resolve pointer to creature?
+							std::shared_ptr<CCreatureTypeLimiter> l2 = std::make_shared<CCreatureTypeLimiter>(); //TODO: How the hell resolve pointer to creature?
 							const JsonVector vec = limiter["parameters"].Vector();
 							VLC->modh->identifiers.requestIdentifier("creature", vec[0], [=](si32 creature)
 							{
@@ -503,7 +503,7 @@ Bonus * JsonUtils::parseBonus (const JsonNode &ability)
 						}
 						if (limiter["type"].String() == "HAS_ANOTHER_BONUS_LIMITER")
 						{
-							shared_ptr<HasAnotherBonusLimiter> l2 = make_shared<HasAnotherBonusLimiter>();
+							std::shared_ptr<HasAnotherBonusLimiter> l2 = std::make_shared<HasAnotherBonusLimiter>();
 							const JsonVector vec = limiter["parameters"].Vector();
 							std::string anotherBonusType = vec[0].String();
 

+ 2 - 5
lib/NetPacks.h

@@ -331,9 +331,6 @@ struct SetAvailableHeroes : public CPackForClient //113
 		for (int i = 0; i < GameConstants::AVAILABLE_HEROES_PER_PLAYER; i++)
 			army[i].clear();
 	}
-	~SetAvailableHeroes()
-	{
-	}
 	void applyCl(CClient *cl);
 	DLL_LINKAGE void applyGs(CGameState *gs);
 
@@ -446,7 +443,7 @@ struct UpdateCampaignState : public CPackForClient //119
 		type = 119;
 	}
 
-	shared_ptr<CCampaignState> camp;
+	std::shared_ptr<CCampaignState> camp;
 	void applyCl(CClient *cl);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -1684,7 +1681,7 @@ struct BattleObstaclePlaced : public CPackForClient //3020
 	DLL_LINKAGE void applyGs(CGameState *gs); //effect
 	void applyCl(CClient *cl); //play animations & stuff
 
-	shared_ptr<CObstacleInstance> obstacle;
+	std::shared_ptr<CObstacleInstance> obstacle;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 8 - 6
lib/NetPacksLib.cpp

@@ -223,7 +223,7 @@ DLL_LINKAGE void FoWChange::applyGs( CGameState *gs )
 				case Obj::TOWN:
 				case Obj::ABANDONED_MINE:
 					if(vstd::contains(team->players, o->tempOwner)) //check owned observators
-						gs->getTilesInRange(tiles, o->getSightCenter(), o->getSightRadious(), o->tempOwner, 1);
+						gs->getTilesInRange(tilesRevealed, o->getSightCenter(), o->getSightRadious(), o->tempOwner, 1);
 					break;
 				}
 			}
@@ -1010,6 +1010,13 @@ DLL_LINKAGE void SetAvailableArtifacts::applyGs( CGameState *gs )
 DLL_LINKAGE void NewTurn::applyGs( CGameState *gs )
 {
 	gs->day = day;
+
+	// Update bonuses before doing anything else so hero don't get more MP than needed
+	gs->globalEffects.popBonuses(Bonus::OneDay); //works for children -> all game objs
+	gs->globalEffects.updateBonuses(Bonus::NDays);
+	gs->globalEffects.updateBonuses(Bonus::OneWeek);
+	//TODO not really a single root hierarchy, what about bonuses placed elsewhere? [not an issue with H3 mechanics but in the future...]
+
 	for(NewTurn::Hero h : heroes) //give mana/movement point
 	{
 		CGHeroInstance *hero = gs->getHero(h.id);
@@ -1026,11 +1033,6 @@ DLL_LINKAGE void NewTurn::applyGs( CGameState *gs )
 	for(auto creatureSet : cres) //set available creatures in towns
 		creatureSet.second.applyGs(gs);
 
-	gs->globalEffects.popBonuses(Bonus::OneDay); //works for children -> all game objs
-	gs->globalEffects.updateBonuses(Bonus::NDays);
-	gs->globalEffects.updateBonuses(Bonus::OneWeek);
-	//TODO not really a single root hierarchy, what about bonuses placed elsewhere? [not an issue with H3 mechanics but in the future...]
-
 	for(CGTownInstance* t : gs->map->towns)
 		t->builded = 0;
 

+ 2 - 2
lib/StartInfo.h

@@ -82,9 +82,9 @@ struct StartInfo
 	ui8 turnTime; //in minutes, 0=unlimited
 	std::string mapname; // empty for random map, otherwise name of the map or savegame
 	bool createRandomMap() const { return mapGenOptions.get() != nullptr; }
-	shared_ptr<CMapGenOptions> mapGenOptions;
+	std::shared_ptr<CMapGenOptions> mapGenOptions;
 
-	shared_ptr<CCampaignState> campState;
+	std::shared_ptr<CCampaignState> campState;
 
 	PlayerSettings & getIthPlayersSettings(PlayerColor no)
 	{

+ 1 - 1
lib/StringConstants.h

@@ -3,7 +3,7 @@
 #include "GameConstants.h"
 
 /*
- * GameConstants.h, part of VCMI engine
+ * StringConstants.h, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *

+ 9 - 0
lib/VCMI_lib.vcxproj

@@ -293,8 +293,10 @@
     <ClInclude Include="Connection.h" />
     <ClInclude Include="ConstTransitivePtr.h" />
     <ClInclude Include="CPathfinder.h" />
+    <ClInclude Include="CPlayerState.h" />
     <ClInclude Include="CRandomGenerator.h" />
     <ClInclude Include="CScriptingModule.h" />
+    <ClInclude Include="CSoundBase.h" />
     <ClInclude Include="CStopWatch.h" />
     <ClInclude Include="CThreadHelper.h" />
     <ClInclude Include="CTownHandler.h" />
@@ -313,6 +315,7 @@
     <ClInclude Include="filesystem\ResourceID.h" />
     <ClInclude Include="FunctionList.h" />
     <ClInclude Include="IBonusTypeHandler.h" />
+    <ClInclude Include="IHandlerBase.h" />
     <ClInclude Include="JsonDetail.h" />
     <ClInclude Include="LogicalExpression.h" />
     <ClInclude Include="mapObjects\CArmedInstance.h" />
@@ -332,12 +335,15 @@
     <ClInclude Include="mapObjects\MiscObjects.h" />
     <ClInclude Include="mapObjects\ObjectTemplate.h" />
     <ClInclude Include="mapping\CCampaignHandler.h" />
+    <ClInclude Include="mapping\CDrawRoadsOperation.h" />
     <ClInclude Include="mapping\CMap.h" />
+    <ClInclude Include="mapping\CMapDefines.h" />
     <ClInclude Include="mapping\CMapInfo.h" />
     <ClInclude Include="mapping\CMapService.h" />
     <ClInclude Include="mapping\CMapEditManager.h" />
     <ClInclude Include="mapping\MapFormatH3M.h" />
     <ClInclude Include="mapping\MapFormatJson.h" />
+    <ClInclude Include="NetPacksBase.h" />
     <ClInclude Include="registerTypes\RegisterTypes.h" />
     <ClInclude Include="rmg\CMapGenerator.h" />
     <ClInclude Include="logging\CLogger.h" />
@@ -360,6 +366,7 @@
     <ClInclude Include="rmg\CZoneGraphGenerator.h" />
     <ClInclude Include="rmg\CZonePlacer.h" />
     <ClInclude Include="rmg\float3.h" />
+    <ClInclude Include="ScopeGuard.h" />
     <ClInclude Include="spells\AdventureSpellMechanics.h" />
     <ClInclude Include="spells\BattleSpellMechanics.h" />
     <ClInclude Include="spells\CDefaultSpellMechanics.h" />
@@ -371,7 +378,9 @@
     <ClInclude Include="spells\ViewSpellInt.h" />
     <ClInclude Include="StartInfo.h" />
     <ClInclude Include="StdInc.h" />
+    <ClInclude Include="StringConstants.h" />
     <ClInclude Include="UnlockGuard.h" />
+    <ClInclude Include="vcmi_endian.h" />
     <ClInclude Include="VCMI_Lib.h" />
     <ClInclude Include="VCMIDirs.h" />
   </ItemGroup>

+ 36 - 3
lib/VCMI_lib.vcxproj.filters

@@ -155,8 +155,6 @@
     <ClCompile Include="registerTypes\TypesClientPacks1.cpp">
       <Filter>registerTypes</Filter>
     </ClCompile>
-    <ClCompile Include="registerTypes\TypesMapObjects1.cpp" />
-    <ClCompile Include="registerTypes\TypesMapObjects2.cpp" />
     <ClCompile Include="mapObjects\CArmedInstance.cpp">
       <Filter>mapObjects</Filter>
     </ClCompile>
@@ -202,7 +200,6 @@
     <ClCompile Include="mapObjects\ObjectTemplate.cpp">
       <Filter>mapObjects</Filter>
     </ClCompile>
-    <ClCompile Include="registerTypes\TypesMapObjects3.cpp" />
     <ClCompile Include="IHandlerBase.cpp" />
     <ClCompile Include="spells\AdventureSpellMechanics.cpp">
       <Filter>spells</Filter>
@@ -227,6 +224,15 @@
     </ClCompile>
     <ClCompile Include="mapping\CDrawRoadsOperation.cpp" />
     <ClCompile Include="CPathfinder.cpp" />
+    <ClCompile Include="registerTypes\TypesMapObjects1.cpp">
+      <Filter>registerTypes</Filter>
+    </ClCompile>
+    <ClCompile Include="registerTypes\TypesMapObjects2.cpp">
+      <Filter>registerTypes</Filter>
+    </ClCompile>
+    <ClCompile Include="registerTypes\TypesMapObjects3.cpp">
+      <Filter>registerTypes</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="CCreatureSet.h">
@@ -541,5 +547,32 @@
     <ClInclude Include="CPathfinder.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="CPlayerState.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="mapping\CMapDefines.h">
+      <Filter>mapping</Filter>
+    </ClInclude>
+    <ClInclude Include="CSoundBase.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="IHandlerBase.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="NetPacksBase.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="ScopeGuard.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="StringConstants.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="vcmi_endian.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="mapping\CDrawRoadsOperation.h">
+      <Filter>mapping</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>

+ 1 - 1
lib/filesystem/CCompressedStream.h

@@ -1,7 +1,7 @@
 #pragma once
 
 /*
- * CLodStream.h, part of VCMI engine
+ * CCompressedStream.h, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *

+ 1 - 1
lib/logging/CLogger.cpp

@@ -134,7 +134,7 @@ void CLogger::setLevel(ELogLevel::ELogLevel level)
 
 const CLoggerDomain & CLogger::getDomain() const { return domain; }
 
-void CLogger::addTarget(unique_ptr<ILogTarget> && target)
+void CLogger::addTarget(std::unique_ptr<ILogTarget> && target)
 {
 	TLockGuard _(mx);
 	targets.push_back(std::move(target));

+ 3 - 3
lib/logging/CLogger.h

@@ -105,7 +105,7 @@ public:
 
 	inline void log(ELogLevel::ELogLevel level, const std::string & message) const;
 
-	void addTarget(unique_ptr<ILogTarget> && target);
+	void addTarget(std::unique_ptr<ILogTarget> && target);
 	void clearTargets();
 
 	/// Returns true if a debug/trace log message will be logged, false if not.
@@ -121,7 +121,7 @@ private:
 	CLoggerDomain domain;
 	CLogger * parent;
 	ELogLevel::ELogLevel level;
-	std::vector<unique_ptr<ILogTarget> > targets;
+	std::vector<std::unique_ptr<ILogTarget> > targets;
 	mutable boost::mutex mx;
 	static boost::recursive_mutex smx;
 };
@@ -149,7 +149,7 @@ private:
 /// the first statement in the function. Logging traces via this macro have almost no impact when the trace is disabled.
 /// 
 #define RAII_TRACE(logger, onEntry, onLeave)			\
-	unique_ptr<CTraceLogger> ctl00;						\
+	std::unique_ptr<CTraceLogger> ctl00;						\
 	if(logger->isTraceEnabled())						\
 		ctl00 = make_unique<CTraceLogger>(logger, onEntry, onLeave);
 

+ 3 - 2
lib/mapObjects/CArmedInstance.cpp

@@ -46,7 +46,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
 	if(!validTypes(false)) //object not randomized, don't bother
 		return;
 
-	Bonus *b = getBonusList().getFirst(Selector::sourceType(Bonus::ARMY).And(Selector::type(Bonus::MORALE)));
+	Bonus *b = getExportedBonusList().getFirst(Selector::sourceType(Bonus::ARMY).And(Selector::type(Bonus::MORALE)));
 	if(!b)
 	{
 		b = new Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, 0, -1);
@@ -96,10 +96,11 @@ void CArmedInstance::updateMoraleBonusFromArmy()
 		b->description = b->description.substr(0, b->description.size()-2);//trim value
 	}
 	boost::algorithm::trim(b->description);
+	CBonusSystemNode::treeHasChanged();
 
 	//-1 modifier for any Undead unit in army
 	const ui8 UNDEAD_MODIFIER_ID = -2;
-	Bonus *undeadModifier = getBonusList().getFirst(Selector::source(Bonus::ARMY, UNDEAD_MODIFIER_ID));
+	Bonus *undeadModifier = getExportedBonusList().getFirst(Selector::source(Bonus::ARMY, UNDEAD_MODIFIER_ID));
  	if(hasUndead)
 	{
 		if(!undeadModifier)

+ 2 - 2
lib/mapObjects/CBank.cpp

@@ -292,9 +292,9 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 			loot.addReplacement(*elem.second);
 		}
 
-		if (ourArmy.Slots().size())
+		if(ourArmy.stacksCount())
 		{
-			if (ourArmy.Slots().size() == 1 && ourArmy.Slots().begin()->second->count == 1)
+			if(ourArmy.stacksCount() == 1 && ourArmy.Slots().begin()->second->count == 1)
 				iw.text.addTxt (MetaString::ADVOB_TXT, 185);
 			else
 				iw.text.addTxt (MetaString::ADVOB_TXT, 186);

+ 4 - 2
lib/mapObjects/CGHeroInstance.cpp

@@ -43,7 +43,7 @@ static void showInfoDialog(const CGHeroInstance* h, const ui32 txtID, const ui16
 
 static int lowestSpeed(const CGHeroInstance * chi)
 {
-	if(!chi->Slots().size())
+	if(!chi->stacksCount())
 	{
         logGlobal->errorStream() << "Error! Hero " << chi->id.getNum() << " ("<<chi->name<<") has no army!";
 		return 20;
@@ -818,7 +818,7 @@ void CGHeroInstance::updateSkill(SecondarySkill which, int val)
 
 
 	Bonus::ValueType skillValType = skillVal ? Bonus::BASE_NUMBER : Bonus::INDEPENDENT_MIN;
-	if(Bonus * b = getBonusList().getFirst(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, which)
+	if(Bonus * b = getExportedBonusList().getFirst(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, which)
 										.And(Selector::sourceType(Bonus::SECONDARY_SKILL)))) //only local hero bonus
 	{
 		b->val = skillVal;
@@ -831,6 +831,7 @@ void CGHeroInstance::updateSkill(SecondarySkill which, int val)
 		addNewBonus(bonus);
 	}
 
+	CBonusSystemNode::treeHasChanged();
 }
 void CGHeroInstance::setPropertyDer( ui8 what, ui32 val )
 {
@@ -1365,6 +1366,7 @@ void CGHeroInstance::setPrimarySkill(PrimarySkill::PrimarySkill primarySkill, si
 		{
 			skill->val += value;
 		}
+		CBonusSystemNode::treeHasChanged();
 	}
 	else if(primarySkill == PrimarySkill::EXPERIENCE)
 	{

+ 1 - 1
lib/mapObjects/CGHeroInstance.h

@@ -79,7 +79,7 @@ public:
 		template <typename Handler> void serialize(Handler &h, const int version)
 		{
 			h & patrolling;
-			if(version >= 755)
+			if(version >= 755) //save format backward compatibility
 			{
 				h & initialPos;
 			}

+ 7 - 7
lib/mapObjects/CGPandoraBox.cpp

@@ -235,7 +235,7 @@ void CGPandoraBox::giveContentsAfterExp(const CGHeroInstance *h) const
 	iw.components.clear();
 	iw.text.clear();
 
-	if (creatures.Slots().size())
+	if(creatures.stacksCount())
 	{ //this part is taken straight from creature bank
 		MetaString loot;
 		for(auto & elem : creatures.Slots())
@@ -245,7 +245,7 @@ void CGPandoraBox::giveContentsAfterExp(const CGHeroInstance *h) const
 			loot.addReplacement(*elem.second);
 		}
 
-		if (creatures.Slots().size() == 1 && creatures.Slots().begin()->second->count == 1)
+		if(creatures.stacksCount() == 1 && creatures.Slots().begin()->second->count == 1)
 			iw.text.addTxt(MetaString::ADVOB_TXT, 185);
 		else
 			iw.text.addTxt(MetaString::ADVOB_TXT, 186);
@@ -303,17 +303,17 @@ void CGPandoraBox::battleFinished(const CGHeroInstance *hero, const BattleResult
 
 void CGPandoraBox::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
 {
-	if (answer)
+	if(answer)
 	{
-		if (stacksCount() > 0) //if pandora's box is protected by army
+		if(stacksCount() > 0) //if pandora's box is protected by army
 		{
 			showInfoDialog(hero,16,0);
 			cb->startBattleI(hero, this); //grants things after battle
 		}
-		else if (message.size() == 0 && resources.size() == 0
+		else if(message.size() == 0 && resources.size() == 0
 			&& primskills.size() == 0 && abilities.size() == 0
-			&& abilityLevels.size() == 0 &&  artifacts.size() == 0
-			&& spells.size() == 0 && creatures.Slots().size() > 0
+			&& abilityLevels.size() == 0 && artifacts.size() == 0
+			&& spells.size() == 0 && creatures.stacksCount() > 0
 			&& gainedExp == 0 && manaDiff == 0 && moraleDiff == 0 && luckDiff == 0) //if it gives nothing without battle
 		{
 			showInfoDialog(hero,15,0);

+ 4 - 1
lib/mapObjects/CGTownInstance.cpp

@@ -856,7 +856,7 @@ void CGTownInstance::deserializationFix()
 
 void CGTownInstance::updateMoraleBonusFromArmy()
 {
-	Bonus *b = getBonusList().getFirst(Selector::sourceType(Bonus::ARMY).And(Selector::type(Bonus::MORALE)));
+	Bonus *b = getExportedBonusList().getFirst(Selector::sourceType(Bonus::ARMY).And(Selector::type(Bonus::MORALE)));
 	if(!b)
 	{
 		b = new Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, 0, -1);
@@ -864,7 +864,10 @@ void CGTownInstance::updateMoraleBonusFromArmy()
 	}
 
 	if (garrisonHero)
+	{
 		b->val = 0;
+		CBonusSystemNode::treeHasChanged();
+	}
 	else
 		CArmedInstance::updateMoraleBonusFromArmy();
 }

+ 1 - 1
lib/mapObjects/CObjectHandler.cpp

@@ -409,7 +409,7 @@ int3 IBoatGenerator::bestLocation() const
 	{
 		if (const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offset, false)) //tile is in the map
 		{
-			if (tile->terType == ETerrainType::WATER  &&  (!tile->blocked || tile->blockingObjects.front()->ID == 8)) //and is water and is not blocked or is blocked by boat
+			if (tile->terType == ETerrainType::WATER  &&  (!tile->blocked || tile->blockingObjects.front()->ID == Obj::BOAT)) //and is water and is not blocked or is blocked by boat
 				return o->pos + offset;
 		}
 	}

+ 3 - 3
lib/mapObjects/CommonConstructors.cpp

@@ -325,10 +325,10 @@ void CBankInstanceConstructor::configureObject(CGObjectInstance * object, CRando
 	}
 }
 
-CBankInfo::CBankInfo(JsonVector config):
-	config(config)
+CBankInfo::CBankInfo(const JsonVector & Config):
+	config(Config)
 {
-	assert(!config.empty());
+	assert(!Config.empty());
 }
 
 static void addStackToArmy(IObjectInfo::CArmyStructure & army, const CCreature * crea, si32 amount)

+ 3 - 2
lib/mapObjects/CommonConstructors.h

@@ -2,6 +2,7 @@
 
 #include "CObjectClassesHandler.h"
 #include "../CTownHandler.h" // for building ID-based filters
+#include "MapObjects.h"
 
 /*
  * CommonConstructors.h, part of VCMI engine
@@ -155,9 +156,9 @@ typedef std::vector<std::pair<ui8, IObjectInfo::CArmyStructure>> TPossibleGuards
 
 class DLL_LINKAGE CBankInfo : public IObjectInfo
 {
-	JsonVector config;
+	const JsonVector & config;
 public:
-	CBankInfo(JsonVector config);
+	CBankInfo(const JsonVector & Config);
 
 	TPossibleGuards getPossibleGuards() const;
 

+ 1 - 1
lib/mapObjects/JsonRandom.cpp

@@ -1,6 +1,6 @@
 /*
  *
- * CRewardableObject.cpp, part of VCMI engine
+ * JsonRandom.cpp, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *

+ 59 - 32
lib/mapObjects/MiscObjects.cpp

@@ -640,7 +640,6 @@ std::string CGMine::getObjectName() const
 
 std::string CGMine::getHoverText(PlayerColor player) const
 {
-
 	std::string hoverName = getObjectName(); // Sawmill
 
 	if (tempOwner != PlayerColor::NEUTRAL)
@@ -650,11 +649,12 @@ std::string CGMine::getHoverText(PlayerColor player) const
 		hoverName += "\n(" + VLC->generaltexth->restypes[producedResource] + ")";
 	}
 
-	for (auto & slot : Slots()) // guarded by a few Pikeman
+	if(stacksCount())
 	{
 		hoverName += "\n";
-		hoverName += getRoughAmount(slot.first);
-		hoverName += getCreature(slot.first)->namePl;
+		hoverName += VLC->generaltexth->allTexts[202]; //Guarded by
+		hoverName += " ";
+		hoverName += getArmyDescription();
 	}
 	return hoverName;
 }
@@ -907,12 +907,12 @@ std::vector<ObjectInstanceID> CGTeleport::getPassableExits(CGameState * gs, cons
 	return exits;
 }
 
-void CGTeleport::addToChannel(std::map<TeleportChannelID, shared_ptr<TeleportChannel> > &channelsList, const CGTeleport * obj)
+void CGTeleport::addToChannel(std::map<TeleportChannelID, std::shared_ptr<TeleportChannel> > &channelsList, const CGTeleport * obj)
 {
-	shared_ptr<TeleportChannel> tc;
+	std::shared_ptr<TeleportChannel> tc;
 	if(channelsList.find(obj->channel) == channelsList.end())
 	{
-		tc = make_shared<TeleportChannel>();
+		tc = std::make_shared<TeleportChannel>();
 		channelsList.insert(std::make_pair(obj->channel, tc));
 	}
 	else
@@ -973,17 +973,18 @@ void CGMonolith::onHeroVisit( const CGHeroInstance * h ) const
 void CGMonolith::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, TTeleportExitsList exits) const
 {
 	int3 dPos;
+	auto randomExit = getRandomExit(hero);
 	auto realExits = getAllExits(true);
 	if(!isEntrance() // Do nothing if hero visited exit only object
 		|| (!exits.size() && !realExits.size()) // Do nothing if there no exits on this channel
-		|| (!exits.size() && ObjectInstanceID() == getRandomExit(hero))) // Do nothing if all exits are blocked by friendly hero and it's not subterranean gate
+		|| ObjectInstanceID() == randomExit) // Do nothing if all exits are blocked by friendly hero and it's not subterranean gate
 	{
 		return;
 	}
 	else if(vstd::isValidIndex(exits, answer))
 		dPos = exits[answer].second;
 	else
-		dPos = CGHeroInstance::convertPosition(cb->getObj(getRandomExit(hero))->visitablePos(), true);
+		dPos = CGHeroInstance::convertPosition(cb->getObj(randomExit)->visitablePos(), true);
 
 	cb->moveHero(hero->id, dPos, true);
 }
@@ -1158,10 +1159,10 @@ void CGWhirlpool::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer
 	cb->moveHero(hero->id, dPos, true);
 }
 
-bool CGWhirlpool::isProtected( const CGHeroInstance * h )
+bool CGWhirlpool::isProtected(const CGHeroInstance * h)
 {
-	if(h->hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION)
-		|| (h->Slots().size() == 1 && h->Slots().begin()->second->count == 1)) //we can't remove last unit
+	if(h->hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION) ||
+		(h->stacksCount() == 1 && h->Slots().begin()->second->count == 1)) //we can't remove last unit
 	{
 		return true;
 	}
@@ -1196,7 +1197,7 @@ std::string CGArtifact::getObjectName() const
 	return VLC->arth->artifacts[subID]->Name();
 }
 
-void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
+void CGArtifact::onHeroVisit(const CGHeroInstance * h) const
 {
 	if(!stacksCount())
 	{
@@ -1207,28 +1208,32 @@ void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
 		case Obj::ARTIFACT:
 			{
 				iw.soundID = soundBase::treasure; //play sound only for non-scroll arts
-				iw.components.push_back(Component(Component::ARTIFACT,subID,0,0));
+				iw.components.push_back(Component(Component::ARTIFACT, subID, 0, 0));
 				if(message.length())
-					iw.text <<  message;
+					iw.text << message;
 				else
 				{
-					if (VLC->arth->artifacts[subID]->EventText().size())
-						iw.text << std::pair<ui8, ui32> (MetaString::ART_EVNTS, subID);
+					if(VLC->arth->artifacts[subID]->EventText().size())
+						iw.text << std::pair<ui8, ui32>(MetaString::ART_EVNTS, subID);
 					else //fix for mod artifacts with no event text
 					{
-						iw.text.addTxt (MetaString::ADVOB_TXT, 183); //% has found treasure
-						iw.text.addReplacement (h->name);
+						iw.text.addTxt(MetaString::ADVOB_TXT, 183); //% has found treasure
+						iw.text.addReplacement(h->name);
 					}
-
 				}
 			}
 			break;
 		case Obj::SPELL_SCROLL:
 			{
 				int spellID = storedArtifact->getGivenSpellID();
-				iw.components.push_back (Component(Component::SPELL, spellID,0,0));
-				iw.text.addTxt (MetaString::ADVOB_TXT,135);
-				iw.text.addReplacement(MetaString::SPELL_NAME, spellID);
+				iw.components.push_back(Component(Component::SPELL, spellID, 0, 0));
+				if(message.length())
+					iw.text << message;
+				else
+				{
+					iw.text.addTxt(MetaString::ADVOB_TXT,135);
+					iw.text.addReplacement(MetaString::SPELL_NAME, spellID);
+				}
 			}
 			break;
 		}
@@ -1237,16 +1242,38 @@ void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
 	}
 	else
 	{
-		if(message.size())
-		{
-			BlockingDialog ynd(true,false);
-			ynd.player = h->getOwner();
-			ynd.text << message;
-			cb->showBlockingDialog(&ynd);
-		}
-		else
+		switch(ID)
 		{
-			blockingDialogAnswered(h, true);
+		case Obj::ARTIFACT:
+			{
+				BlockingDialog ynd(true,false);
+				ynd.player = h->getOwner();
+				if(message.length())
+					ynd.text << message;
+				else
+				{
+					// TODO: Guard text is more complex in H3, see mantis issue 2325 for details
+					ynd.text.addTxt(MetaString::GENERAL_TXT, 420);
+					ynd.text.addReplacement("");
+					ynd.text.addReplacement(getArmyDescription());
+					ynd.text.addReplacement(MetaString::GENERAL_TXT, 43); // creatures
+				}
+				cb->showBlockingDialog(&ynd);
+			}
+			break;
+		case Obj::SPELL_SCROLL:
+			{
+				if(message.length())
+				{
+					BlockingDialog ynd(true,false);
+					ynd.player = h->getOwner();
+					ynd.text << message;
+					cb->showBlockingDialog(&ynd);
+				}
+				else
+					blockingDialogAnswered(h, true);
+			}
+			break;
 		}
 	}
 }

+ 1 - 1
lib/mapObjects/MiscObjects.h

@@ -317,7 +317,7 @@ public:
 	static bool isTeleport(const CGObjectInstance * dst);
 	static bool isConnected(const CGTeleport * src, const CGTeleport * dst);
 	static bool isConnected(const CGObjectInstance * src, const CGObjectInstance * dst);
-	static void addToChannel(std::map<TeleportChannelID, shared_ptr<TeleportChannel> > &channelsList, const CGTeleport * obj);
+	static void addToChannel(std::map<TeleportChannelID, std::shared_ptr<TeleportChannel> > &channelsList, const CGTeleport * obj);
 	static std::vector<ObjectInstanceID> getPassableExits(CGameState * gs, const CGHeroInstance * h, std::vector<ObjectInstanceID> exits);
 	static bool isExitPassable(CGameState * gs, const CGHeroInstance * h, const CGObjectInstance * obj);
 

+ 2 - 2
lib/mapping/CCampaignHandler.cpp

@@ -40,7 +40,7 @@ CCampaignHeader CCampaignHandler::getHeader( const std::string & name)
 	return ret;
 }
 
-unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & name )
+std::unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & name )
 {
 	auto ret = make_unique<CCampaign>();
 
@@ -411,7 +411,7 @@ CCampaignState::CCampaignState()
 
 }
 
-CCampaignState::CCampaignState( unique_ptr<CCampaign> _camp ) : camp(std::move(_camp))
+CCampaignState::CCampaignState( std::unique_ptr<CCampaign> _camp ) : camp(std::move(_camp))
 {
 	for(int i = 0; i < camp->scenarios.size(); i++)
 	{

+ 3 - 3
lib/mapping/CCampaignHandler.h

@@ -144,7 +144,7 @@ public:
 class DLL_LINKAGE CCampaignState
 {
 public:
-	unique_ptr<CCampaign> camp;
+	std::unique_ptr<CCampaign> camp;
 	std::string campaignName; 
 	std::vector<ui8> mapsConquered, mapsRemaining;
 	boost::optional<si32> currentMap;
@@ -159,7 +159,7 @@ public:
 	ui8 currentBonusID() const;
 
 	CCampaignState();
-	CCampaignState(unique_ptr<CCampaign> _camp);
+	CCampaignState(std::unique_ptr<CCampaign> _camp);
 	~CCampaignState(){};
 
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -184,5 +184,5 @@ public:
 
 	static CCampaignHeader getHeader( const std::string & name); //name - name of appropriate file
 
-	static unique_ptr<CCampaign> getCampaign(const std::string & name); //name - name of appropriate file
+	static std::unique_ptr<CCampaign> getCampaign(const std::string & name); //name - name of appropriate file
 };

+ 1 - 1
lib/mapping/CMap.cpp

@@ -153,7 +153,7 @@ EDiggingStatus TerrainTile::getDiggingStatus(const bool excludeTop) const
 		return EDiggingStatus::CAN_DIG;
 }
 
-bool TerrainTile::hasFavourableWinds() const
+bool TerrainTile::hasFavorableWinds() const
 {
 	return extTileFlags & 128;
 }

+ 2 - 2
lib/mapping/CMap.h

@@ -319,12 +319,12 @@ public:
 
 	//Helper lists
 	std::vector< ConstTransitivePtr<CGHeroInstance> > heroesOnMap;
-	std::map<TeleportChannelID, shared_ptr<TeleportChannel> > teleportChannels;
+	std::map<TeleportChannelID, std::shared_ptr<TeleportChannel> > teleportChannels;
 
 	/// associative list to identify which hero/creature id belongs to which object id(index for objects)
 	std::map<si32, ObjectInstanceID> questIdentifierToId;
 
-	unique_ptr<CMapEditManager> editManager;
+	std::unique_ptr<CMapEditManager> editManager;
 
 	int3 ***guardingCreaturePositions;
 

+ 2 - 2
lib/mapping/CMapDefines.h

@@ -71,7 +71,7 @@ struct DLL_LINKAGE TerrainTile
 	CGObjectInstance * topVisitableObj(bool excludeTop = false) const;
 	bool isWater() const;
 	EDiggingStatus getDiggingStatus(const bool excludeTop = true) const;
-	bool hasFavourableWinds() const;
+	bool hasFavorableWinds() const;
 
 	ETerrainType terType;
 	ui8 terView;
@@ -80,7 +80,7 @@ struct DLL_LINKAGE TerrainTile
 	ERoadType::ERoadType roadType;
 	ui8 roadDir;
 	/// first two bits - how to rotate terrain graphic (next two - river graphic, next two - road);
-	///	7th bit - whether tile is coastal (allows disembarking if land or block movement if water); 8th bit - Favourable Winds effect
+	///	7th bit - whether tile is coastal (allows disembarking if land or block movement if water); 8th bit - Favorable Winds effect
 	ui8 extTileFlags;
 	bool visitable;
 	bool blocked;

+ 3 - 3
lib/mapping/CMapEditManager.cpp

@@ -189,7 +189,7 @@ const CMapOperation * CMapUndoManager::peekUndo() const
 	return peek(undoStack);
 }
 
-void CMapUndoManager::addOperation(unique_ptr<CMapOperation> && operation)
+void CMapUndoManager::addOperation(std::unique_ptr<CMapOperation> && operation)
 {
 	undoStack.push_front(std::move(operation));
 	if(undoStack.size() > undoRedoLimit) undoStack.pop_back();
@@ -252,7 +252,7 @@ void CMapEditManager::insertObject(CGObjectInstance * obj, const int3 & pos)
 	execute(make_unique<CInsertObjectOperation>(map, obj, pos));
 }
 
-void CMapEditManager::execute(unique_ptr<CMapOperation> && operation)
+void CMapEditManager::execute(std::unique_ptr<CMapOperation> && operation)
 {
 	operation->execute();
 	undoManager.addOperation(std::move(operation));
@@ -302,7 +302,7 @@ void CComposedOperation::redo()
 	}
 }
 
-void CComposedOperation::addOperation(unique_ptr<CMapOperation> && operation)
+void CComposedOperation::addOperation(std::unique_ptr<CMapOperation> && operation)
 {
 	operations.push_back(std::move(operation));
 }

+ 5 - 5
lib/mapping/CMapEditManager.h

@@ -144,10 +144,10 @@ public:
 	const CMapOperation * peekRedo() const;
 	const CMapOperation * peekUndo() const;
 
-	void addOperation(unique_ptr<CMapOperation> && operation); /// Client code does not need to call this method.
+	void addOperation(std::unique_ptr<CMapOperation> && operation); /// Client code does not need to call this method.
 
 private:
-	typedef std::list<unique_ptr<CMapOperation> > TStack;
+	typedef std::list<std::unique_ptr<CMapOperation> > TStack;
 
 	void doOperation(TStack & fromStack, TStack & toStack, bool doUndo);
 	const CMapOperation * peek(const TStack & stack) const;
@@ -182,7 +182,7 @@ public:
 	CMapUndoManager & getUndoManager();
 
 private:
-	void execute(unique_ptr<CMapOperation> && operation);
+	void execute(std::unique_ptr<CMapOperation> && operation);
 
 	CMap * map;
 	CMapUndoManager undoManager;
@@ -205,10 +205,10 @@ public:
 	void undo() override;
 	void redo() override;
 
-	void addOperation(unique_ptr<CMapOperation> && operation);
+	void addOperation(std::unique_ptr<CMapOperation> && operation);
 
 private:
-	std::list<unique_ptr<CMapOperation> > operations;
+	std::list<std::unique_ptr<CMapOperation> > operations;
 };
 
 namespace ETerrainGroup

+ 4 - 4
lib/mapping/CMapInfo.h

@@ -1,8 +1,8 @@
 #pragma once
 
 // Forward class declarations aren't enough here. The compiler
-// generated CMapInfo d-tor, generates the unique_ptr d-tor as well here
-// as a inline method. The unique_ptr d-tor requires a complete type. Defining
+// generated CMapInfo d-tor, generates the std::unique_ptr d-tor as well here
+// as a inline method. The std::unique_ptr d-tor requires a complete type. Defining
 // the CMapInfo d-tor to let the compiler add the d-tor stuff in the .cpp file
 // would work with one exception. It prevents the generation of the move
 // constructor which is needed. (Writing such a c-tor is nasty.) With the
@@ -20,8 +20,8 @@ struct StartInfo;
 class DLL_LINKAGE CMapInfo
 {
 public:
-	unique_ptr<CMapHeader> mapHeader; //may be nullptr if campaign
-	unique_ptr<CCampaignHeader> campaignHeader; //may be nullptr if scenario
+	std::unique_ptr<CMapHeader> mapHeader; //may be nullptr if campaign
+	std::unique_ptr<CCampaignHeader> campaignHeader; //may be nullptr if scenario
 	StartInfo * scenarioOpts; //options with which scenario has been started (used only with saved games)
 	std::string fileURI;
 	std::string date;

+ 1 - 1
lib/rmg/CMapGenerator.h

@@ -52,7 +52,7 @@ class DLL_LINKAGE CMapGenerator
 {
 public:
 	explicit CMapGenerator();
-	~CMapGenerator(); // required due to unique_ptr
+	~CMapGenerator(); // required due to std::unique_ptr
 
 	std::unique_ptr<CMap> generate(CMapGenOptions * mapGenOptions, int RandomSeed = std::time(nullptr));
 	

+ 1 - 1
lib/rmg/CZoneGraphGenerator.cpp

@@ -28,7 +28,7 @@ CZoneGraphGenerator::CZoneGraphGenerator()// : gen(nullptr)
 
 }
 
-unique_ptr<CZoneGraph> CZoneGraphGenerator::generate(const CMapGenOptions & options, CRandomGenerator * gen)
+std::unique_ptr<CZoneGraph> CZoneGraphGenerator::generate(const CMapGenOptions & options, CRandomGenerator * gen)
 {
 	return make_unique<CZoneGraph>();
 }

部分文件因为文件数量过多而无法显示