Browse Source

Something that compiles.

DjWarmonger 11 years ago
parent
commit
57fa905a2b
73 changed files with 938 additions and 947 deletions
  1. 3 3
      AI/VCAI/Goals.cpp
  2. 8 7
      AI/VCAI/VCAI.cpp
  3. 6 1
      CMakeLists.txt
  4. 9 0
      ChangeLog
  5. 5 1
      Global.h
  6. 1 1
      client/AdventureMapClasses.cpp
  7. 1 2
      client/CAdvmapInterface.cpp
  8. 2 2
      client/CKingdomInterface.cpp
  9. 1 1
      client/CMT.cpp
  10. 43 49
      client/CPlayerInterface.cpp
  11. 1 1
      client/CQuestLog.cpp
  12. 3 1
      client/Client.h
  13. 5 5
      client/GUIClasses.cpp
  14. 1 0
      client/NetPacksClient.cpp
  15. 1 0
      client/battle/CBattleInterfaceClasses.cpp
  16. 28 17
      client/mapHandler.cpp
  17. 2 1
      client/mapHandler.h
  18. 118 99
      config/objects/generic.json
  19. 42 3
      config/objects/moddables.json
  20. 43 36
      config/objects/rewardable.json
  21. 5 0
      config/schemas/mod.json
  22. 2 4
      lib/BattleState.cpp
  23. 4 5
      lib/BattleState.h
  24. 2 2
      lib/CArtHandler.h
  25. 2 2
      lib/CBattleCallback.cpp
  26. 1 0
      lib/CCreatureSet.cpp
  27. 1 12
      lib/CGameInfoCallback.cpp
  28. 0 1
      lib/CGameInfoCallback.h
  29. 2 56
      lib/CGameState.cpp
  30. 1 65
      lib/CGameState.h
  31. 120 0
      lib/CGameStateFwd.h
  32. 2 1
      lib/CMakeLists.txt
  33. 3 0
      lib/IGameCallback.cpp
  34. 2 1
      lib/IGameCallback.h
  35. 19 0
      lib/IHandlerBase.cpp
  36. 6 4
      lib/IHandlerBase.h
  37. 21 56
      lib/NetPacks.h
  38. 2 2
      lib/NetPacksBase.h
  39. 42 11
      lib/NetPacksLib.cpp
  40. 1 0
      lib/VCMI_lib.cbp
  41. 2 0
      lib/VCMI_lib.vcxproj
  42. 4 0
      lib/VCMI_lib.vcxproj.filters
  43. 3 0
      lib/mapObjects/CArmedInstance.h
  44. 6 3
      lib/mapObjects/CBank.cpp
  45. 1 1
      lib/mapObjects/CBank.h
  46. 9 8
      lib/mapObjects/CGHeroInstance.cpp
  47. 4 2
      lib/mapObjects/CGHeroInstance.h
  48. 3 0
      lib/mapObjects/CGMarket.cpp
  49. 2 0
      lib/mapObjects/CGPandoraBox.cpp
  50. 3 0
      lib/mapObjects/CGPandoraBox.h
  51. 19 15
      lib/mapObjects/CGTownInstance.cpp
  52. 5 3
      lib/mapObjects/CGTownInstance.h
  53. 4 2
      lib/mapObjects/CObjectClassesHandler.cpp
  54. 2 1
      lib/mapObjects/CObjectClassesHandler.h
  55. 24 87
      lib/mapObjects/CObjectHandler.cpp
  56. 53 28
      lib/mapObjects/CObjectHandler.h
  57. 14 30
      lib/mapObjects/CQuest.cpp
  58. 6 4
      lib/mapObjects/CQuest.h
  59. 3 1
      lib/mapObjects/CRewardableConstructor.cpp
  60. 11 10
      lib/mapObjects/CRewardableObject.cpp
  61. 3 1
      lib/mapObjects/CRewardableObject.h
  62. 2 0
      lib/mapObjects/CommonConstructors.cpp
  63. 6 4
      lib/mapObjects/JsonRandom.cpp
  64. 14 14
      lib/mapObjects/JsonRandom.h
  65. 111 93
      lib/mapObjects/MiscObjects.cpp
  66. 19 8
      lib/mapObjects/MiscObjects.h
  67. 1 1
      lib/mapping/CMap.cpp
  68. 10 161
      lib/mapping/MapFormatH3M.cpp
  69. 1 1
      lib/registerTypes/RegisterTypes.h
  70. 2 2
      scripting/erm/ERMInterpreter.cpp
  71. 25 11
      server/CGameHandler.cpp
  72. 3 2
      server/CGameHandler.h
  73. 2 2
      server/CQuery.cpp

+ 3 - 3
AI/VCAI/Goals.cpp

@@ -66,7 +66,7 @@ std::string Goals::AbstractGoal::name() const //TODO: virtualize
 		{
 			auto obj = cb->getObjInstance(ObjectInstanceID(objid));
 			if (obj)
-				desc = "GET OBJ " + obj->getHoverText();
+				desc = "GET OBJ " + obj->getObjectName();
 		}
 		case FIND_OBJ:
 			desc = "FIND OBJ " + boost::lexical_cast<std::string>(objid);
@@ -75,7 +75,7 @@ std::string Goals::AbstractGoal::name() const //TODO: virtualize
 		{
 			auto obj = cb->getObjInstance(ObjectInstanceID(objid));
 			if (obj)
-				desc = "VISIT HERO " + obj->getHoverText();
+				desc = "VISIT HERO " + obj->getObjectName();
 		}
 			break;
 		case GET_ART_TYPE:
@@ -493,7 +493,7 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals()
 
 			if (topObj->ID == Obj::HERO && cb->getPlayerRelations(h->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES)
 				if (topObj != hero.get(true)) //the hero we want to free
-					logAi->errorStream() << boost::format("%s stands in the way of %s") % topObj->getHoverText()  % h->getHoverText();
+					logAi->errorStream() << boost::format("%s stands in the way of %s") % topObj->getObjectName()  % h->getObjectName();
 			if (topObj->ID == Obj::QUEST_GUARD || topObj->ID == Obj::BORDERGUARD)
 			{
 				if (shouldVisit(h, topObj))

+ 8 - 7
AI/VCAI/VCAI.cpp

@@ -5,6 +5,7 @@
 #include "../../lib/mapObjects/MapObjects.h"
 #include "../../lib/CConfigHandler.h"
 #include "../../lib/CHeroHandler.h"
+#include "../../lib/CModHandler.h"
 
 
 /*
@@ -81,7 +82,7 @@ struct ObjInfo
 	ObjInfo(){}
 	ObjInfo(const CGObjectInstance *obj):
 		pos(obj->pos),
-		name(obj->getHoverText())
+		name(obj->getObjectName())
 	{
 	}
 };
@@ -195,7 +196,7 @@ void VCAI::showShipyardDialog(const IShipyard *obj)
 
 void VCAI::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult)
 {
-	LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult);
+	LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf);
 	NET_EVENT_HANDLER;
 	logAi->debugStream() << boost::format("Player %d: I heard that player %d %s.") % playerID % player.getNum() % (victoryLossCheckResult.victory() ? "won" : "lost");
 	if(player == playerID)
@@ -241,7 +242,7 @@ void VCAI::artifactDisassembled(const ArtifactLocation &al)
 
 void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start)
 {
-	LOG_TRACE_PARAMS(logAi, "start '%i'; obj '%s'", start % (visitedObj ? visitedObj->hoverName : std::string("n/a")));
+	LOG_TRACE_PARAMS(logAi, "start '%i'; obj '%s'", start % (visitedObj ? visitedObj->getObjectName() : std::string("n/a")));
 	NET_EVENT_HANDLER;
 	if(start)
 	{
@@ -780,13 +781,13 @@ void VCAI::makeTurnInternal()
 bool VCAI::goVisitObj(const CGObjectInstance * obj, HeroPtr h)
 {
 	int3 dst = obj->visitablePos();
-    logAi->debugStream() << boost::format("%s will try to visit %s at (%s)") % h->name % obj->getHoverText() % strFromInt3(dst);
+	logAi->debugStream() << boost::format("%s will try to visit %s at (%s)") % h->name % obj->getObjectName() % strFromInt3(dst);
 	return moveHeroToTile(dst, h);
 }
 
 void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
 {
-	LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->name % obj->getHoverText() % obj->pos);
+	LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->name % obj->getObjectName() % obj->pos);
 	switch (obj->ID)
 	{
 		case Obj::CREATURE_GENERATOR1:
@@ -1434,7 +1435,7 @@ void VCAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int
 	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
-	battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (presumedEnemy ? presumedEnemy->hoverName : "unknown enemy") % tile);
+	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);
 }
 
@@ -1468,7 +1469,7 @@ void VCAI::reserveObject(HeroPtr h, const CGObjectInstance *obj)
 {
 	reservedObjs.insert(obj);
 	reservedHeroesMap[h].insert(obj);
-	logAi->debugStream() << "reserved object id=" << obj->id << "; address=" << (intptr_t)obj << "; name=" << obj->getHoverText();
+	logAi->debugStream() << "reserved object id=" << obj->id << "; address=" << (intptr_t)obj << "; name=" << obj->getObjectName();
 }
 
 void VCAI::unreserveObject(HeroPtr h, const CGObjectInstance *obj)

+ 6 - 1
CMakeLists.txt

@@ -100,9 +100,14 @@ endif()
 
 if(CMAKE_COMPILER_IS_GNUCXX OR NOT WIN32) #so far all *nix compilers support such parameters
 	if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
-                set(CLANG_SPECIFIC_FLAGS "-Wno-mismatched-tags")
+		set(CLANG_SPECIFIC_FLAGS "-Wno-mismatched-tags")
 	endif()
 	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -Wextra -Wpointer-arith -Wno-switch -Wno-sign-compare -Wno-unused-parameter -Wuninitialized -Wno-overloaded-virtual ${CLANG_SPECIFIC_FLAGS}")
+
+	if(UNIX)
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
+	endif()
+
 endif()
 
 if(WIN32) # on Win everything goes into H3 root directory

+ 9 - 0
ChangeLog

@@ -3,6 +3,7 @@ GENERAL:
 * (linux) now VCMI follows XDG specifications. See http://forum.vcmi.eu/viewtopic.php?t=858
 
 ADVENTURE AI:
+* Optimized speed and removed various bottlenecks.
 
 ADVENTURE MAP:
 * Heroes auto-level primary and secondary skill levels according to experience
@@ -13,6 +14,14 @@ BATTLES:
 SPELLS:
 * New configuration format: http://wiki.vcmi.eu/index.php?title=Spell_Format
 
+RANDOM MAP GENERATOR
+* Towns form mods cna be used
+* Reading connections, terrains, towns and mines from template
+* Zone placement
+* Zone borders and connections, fractalized paths inside zones
+* Guard generation
+* Treasue piles generation (so far only few removable objects)
+
 MODS:
 * Support for submods - mod may have their own "submods" located in <modname>/Mods directory
 * Mods may provide their own changelogs and screenshots that will be visible in Launcher

+ 5 - 1
Global.h

@@ -152,9 +152,11 @@ typedef boost::lock_guard<boost::recursive_mutex> TLockGuardRec;
 #  else
 #    define DLL_EXPORT __declspec(dllexport)
 #  endif
+#  define ELF_VISIBILITY
 #else
 #  ifdef __GNUC__
-#    define DLL_EXPORT	__attribute__ ((visibility("default")))
+#    define DLL_EXPORT __attribute__ ((visibility("default")))
+#    define ELF_VISIBILITY __attribute__ ((visibility("default")))
 #  endif
 #endif
 
@@ -164,9 +166,11 @@ typedef boost::lock_guard<boost::recursive_mutex> TLockGuardRec;
 #  else
 #    define DLL_IMPORT __declspec(dllimport)
 #  endif
+#  define ELF_VISIBILITY
 #else
 #  ifdef __GNUC__
 #    define DLL_IMPORT	__attribute__ ((visibility("default")))
+#    define ELF_VISIBILITY __attribute__ ((visibility("default")))
 #  endif
 #endif
 

+ 1 - 1
client/AdventureMapClasses.cpp

@@ -317,7 +317,7 @@ void CTownList::CTownItem::showTooltip()
 
 std::string CTownList::CTownItem::getHoverText()
 {
-	return town->hoverName;
+	return town->getObjectName();
 }
 
 CTownList::CTownList(int size, Point position, std::string btnUp, std::string btnDown):

+ 1 - 2
client/CAdvmapInterface.cpp

@@ -1234,10 +1234,9 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
 	}
 	const CGObjectInstance *objAtTile = getBlockingObject(mapPos);
 
-	//std::vector<std::string> temp = LOCPLINT->cb->getObjDescriptions(mapPos);
 	if (objAtTile)
 	{
-		std::string text = objAtTile->getHoverText();
+		std::string text = curHero() ? objAtTile->getHoverText(curHero()) : objAtTile->getHoverText(LOCPLINT->playerID);
 		boost::replace_all(text,"\n"," ");
 		statusbar.setText(text);
 	}

+ 2 - 2
client/CKingdomInterface.cpp

@@ -500,7 +500,7 @@ void CKingdomInterface::generateObjectsList(const std::vector<const CGObjectInst
 			OwnedObjectInfo &info = visibleObjects[object->subID];
 			if (info.count++ == 0)
 			{
-				info.hoverText = object->getHoverText();
+				info.hoverText = object->getObjectName();
 				info.imageID = object->subID;
 			}
 		}
@@ -511,7 +511,7 @@ void CKingdomInterface::generateObjectsList(const std::vector<const CGObjectInst
 			OwnedObjectInfo &info = visibleObjects[iter->second];
 			if (info.count++ == 0)
 			{
-				info.hoverText = object->hoverName;
+				info.hoverText = object->getObjectName();
 				info.imageID = iter->second;
 			}
 		}

+ 1 - 1
client/CMT.cpp

@@ -589,7 +589,7 @@ void processCommand(const std::string &message)
 	}
 	else if(cn == "bonuses")
 	{
-        std::cout << "Bonuses of " << adventureInt->selection->getHoverText() << std::endl
+		std::cout << "Bonuses of " << adventureInt->selection->getObjectName() << std::endl
 			<< adventureInt->selection->getBonusList() << std::endl;
 
         std::cout << "\nInherited bonuses:\n";

+ 43 - 49
client/CPlayerInterface.cpp

@@ -91,16 +91,10 @@ CondSh<EMoveState> stillMoveHero; //used during hero movement
 
 int CPlayerInterface::howManyPeople = 0;
 
-
-struct OCM_HLP_CGIN
+static bool objectBlitOrderSorter(const std::pair<const CGObjectInstance*,SDL_Rect>  & a, const std::pair<const CGObjectInstance*,SDL_Rect> & b)
 {
-	bool inline operator ()(const std::pair<const CGObjectInstance*,SDL_Rect>  & a, const std::pair<const CGObjectInstance*,SDL_Rect> & b) const
-	{
-		return (*a.first)<(*b.first);
-	}
-} ocmptwo_cgin ;
-
-
+	return CMapHandler::compareObjectBlitOrder(a.first, b.first);
+}
 
 CPlayerInterface::CPlayerInterface(PlayerColor Player)
 {
@@ -1708,14 +1702,14 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
 		subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 33), ho->id);
 		subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 33), ho->id);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), objectBlitOrderSorter);
 	}
 	else if(details.end.x == details.start.x && details.end.y+1 == details.start.y) //t
 	{
@@ -1733,9 +1727,9 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
 		subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 33), ho->id);
 		subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 33), ho->id);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter);
 	}
 	else if(details.end.x-1 == details.start.x && details.end.y+1 == details.start.y) //tr
 	{
@@ -1756,14 +1750,14 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
 		subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 33), ho->id);
 		CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 33)));
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), objectBlitOrderSorter);
 	}
 	else if(details.end.x-1 == details.start.x && details.end.y == details.start.y) //r
 	{
@@ -1779,9 +1773,9 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
 		subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 32), ho->id);
 		CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 32)));
 
-		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), objectBlitOrderSorter);
 	}
 	else if(details.end.x-1 == details.start.x && details.end.y-1 == details.start.y) //br
 	{
@@ -1802,14 +1796,14 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
 		CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 63, 63)));
 		CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 63)));
 
-		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), objectBlitOrderSorter);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter);
 	}
 	else if(details.end.x == details.start.x && details.end.y-1 == details.start.y) //b
 	{
@@ -1827,9 +1821,9 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
 		CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 32, 63)));
 		CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 64, 63)));
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter);
 	}
 	else if(details.end.x+1 == details.start.x && details.end.y-1 == details.start.y) //bl
 	{
@@ -1850,14 +1844,14 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
 		CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 33, 63)));
 		CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 65, 63)));
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), objectBlitOrderSorter);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
-		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter);
+		std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter);
 	}
 	else if(details.end.x+1 == details.start.x && details.end.y == details.start.y) //l
 	{
@@ -1873,9 +1867,9 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
 		subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 32), ho->id);
 		subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 32), ho->id);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter);
 
-		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), ocmptwo_cgin);
+		std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), objectBlitOrderSorter);
 	}
 }
 
@@ -2105,13 +2099,13 @@ void CPlayerInterface::finishMovement( const TryMoveHero &details, const int3 &h
 	subRect(details.end.x, details.end.y, details.end.z, genRect(32, 32, 64, 32), ho->id);
 
 	//restoring good order of objects
-	std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.end(), ocmptwo_cgin);
-	std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.end(), ocmptwo_cgin);
-	std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.end(), ocmptwo_cgin);
+	std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.end(), objectBlitOrderSorter);
+	std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.end(), objectBlitOrderSorter);
+	std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.end(), objectBlitOrderSorter);
 
-	std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.end(), ocmptwo_cgin);
-	std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.end(), ocmptwo_cgin);
-	std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.end(), ocmptwo_cgin);
+	std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.end(), objectBlitOrderSorter);
+	std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.end(), objectBlitOrderSorter);
+	std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.end(), objectBlitOrderSorter);
 }
 
 void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult )

+ 1 - 1
client/CQuestLog.cpp

@@ -140,7 +140,7 @@ void CQuestLog::init()
 		MetaString text;
 		quests[i].quest->getRolloverText (text, false);
 		if (quests[i].obj)
-			text.addReplacement (quests[i].obj->getHoverText()); //get name of the object
+			text.addReplacement (quests[i].obj->getObjectName()); //get name of the object
 		CQuestLabel * label = new CQuestLabel (Rect(28, 199 + i * 24, 172,30), FONT_SMALL, TOPLEFT, Colors::WHITE, text.toString());
 		label->callback = boost::bind(&CQuestLog::selectQuest, this, i);
 		labels.push_back(label);

+ 3 - 1
client/Client.h

@@ -170,7 +170,6 @@ public:
 	bool removeObject(const CGObjectInstance * obj) override {return false;};
 	void setBlockVis(ObjectInstanceID objid, bool bv) override {};
 	void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {};
-	void setHoverName(const CGObjectInstance * obj, MetaString * name) override {};
 	void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false) override {};
 	void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) override {}; 
 
@@ -218,6 +217,9 @@ public:
 	void sendAndApply(CPackForClient * info) override {};
 	void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override {};
 
+	void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override {}
+	void changeFogOfWar(std::unordered_set<int3, ShashInt3> &tiles, PlayerColor player, bool hide) override {}
+
 	//////////////////////////////////////////////////////////////////////////
 	friend class CCallback; //handling players actions
 	friend class CBattleCallback; //handling players actions

+ 5 - 5
client/GUIClasses.cpp

@@ -1848,7 +1848,7 @@ CObjectListWindow::CObjectListWindow(const std::vector<int> &_items, CIntObject
 	items.reserve(_items.size());
 	for(int id : _items)
 	{
-		items.push_back(std::make_pair(id, CGI->mh->map->objects[id]->hoverName));
+		items.push_back(std::make_pair(id, CGI->mh->map->objects[id]->getObjectName()));
 	}
 
 	init(titlePic, _title, _descr);
@@ -2614,7 +2614,7 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan
 		break; case Obj::BLACK_MARKET:   title = CGI->generaltexth->allTexts[349];
 		break; case Obj::TRADING_POST:  title = CGI->generaltexth->allTexts[159];
 		break; case Obj::TRADING_POST_SNOW: title = CGI->generaltexth->allTexts[159];
-		break; default:  title = market->o->getHoverText();
+		break; default:  title = market->o->getObjectName();
 		}
 	}
 
@@ -4571,7 +4571,7 @@ void CHeroArea::clickRight(tribool down, bool previousState)
 void CHeroArea::hover(bool on)
 {
 	if (on && hero)
-		GH.statusbar->setText(hero->hoverName);
+		GH.statusbar->setText(hero->getObjectName());
 	else
 		GH.statusbar->clear();
 }
@@ -5634,7 +5634,7 @@ CHillFortWindow::CHillFortWindow(const CGHeroInstance *visitor, const CGObjectIn
 	slotsCount=7;
 	resources =  CDefHandler::giveDefEss("SMALRES.DEF");
 
-	new CLabel(325, 32, FONT_BIG, CENTER, Colors::YELLOW, fort->hoverName);//Hill Fort
+	new CLabel(325, 32, FONT_BIG, CENTER, Colors::YELLOW, fort->getObjectName());//Hill Fort
 
 	heroPic = new CHeroArea(30, 60, hero);
 
@@ -6181,7 +6181,7 @@ void CRClickPopup::createAndPush(const CGObjectInstance *obj, const Point &p, EA
 	if(iWin)
 		GH.pushInt(iWin);
 	else
-		CRClickPopup::createAndPush(obj->getHoverText());
+		CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->playerID));
 }
 
 CRClickPopup::CRClickPopup()

+ 1 - 0
client/NetPacksClient.cpp

@@ -15,6 +15,7 @@
 #include "../lib/VCMIDirs.h"
 #include "../lib/CSpellHandler.h"
 #include "../lib/CSoundBase.h"
+#include "../lib/StartInfo.h"
 #include "mapHandler.h"
 #include "GUIClasses.h"
 #include "../lib/CConfigHandler.h"

+ 1 - 0
client/battle/CBattleInterfaceClasses.cpp

@@ -17,6 +17,7 @@
 #include "../../lib/NetPacks.h"
 #include "../../lib/CCreatureHandler.h"
 #include "../../lib/BattleState.h"
+#include "../../lib/StartInfo.h"
 #include "../CMusicHandler.h"
 #include "../CVideoHandler.h"
 #include "../../lib/CTownHandler.h"

+ 28 - 17
client/mapHandler.cpp

@@ -75,21 +75,10 @@ std::string nameFromType (int typ)
 	return std::string();
 }
 
-struct OCM_HLP
+static bool objectBlitOrderSorter(const std::pair<const CGObjectInstance*,SDL_Rect>  & a, const std::pair<const CGObjectInstance*,SDL_Rect> & b)
 {
-	bool operator ()(const std::pair<const CGObjectInstance*, SDL_Rect> & a, const std::pair<const CGObjectInstance*, SDL_Rect> & b)
-	{
-		return (*a.first)<(*b.first);
-	}
-} ocmptwo ;
-
-// void alphaTransformDef(CGDefInfo * defInfo)
-// {	
-// 	for(int yy=0; yy<defInfo->handler->ourImages.size(); ++yy)
-// 	{
-// 		CSDL_Ext::alphaTransform(defInfo->handler->ourImages[yy].bitmap);
-// 	}
-// }
+	return CMapHandler::compareObjectBlitOrder(a.first, b.first);
+}
 
 void CMapHandler::prepareFOWDefs()
 {
@@ -308,7 +297,7 @@ void CMapHandler::initObjectRects()
 		{
 			for(int iz=0; iz<ttiles[0][0].size(); ++iz)
 			{
-				stable_sort(ttiles[ix][iy][iz].objects.begin(), ttiles[ix][iy][iz].objects.end(), ocmptwo);
+				stable_sort(ttiles[ix][iy][iz].objects.begin(), ttiles[ix][iy][iz].objects.end(), objectBlitOrderSorter);
 			}
 		}
 	}
@@ -860,7 +849,7 @@ bool CMapHandler::printObject(const CGObjectInstance *obj)
 				auto i = curt.objects.begin();
 				for(; i != curt.objects.end(); i++)
 				{
-					if(ocmptwo(toAdd, *i))
+					if(objectBlitOrderSorter(toAdd, *i))
 					{
 						curt.objects.insert(i, toAdd);
 						i = curt.objects.begin(); //to validate and avoid adding it second time
@@ -1065,7 +1054,7 @@ void CMapHandler::getTerrainDescr( const int3 &pos, std::string & out, bool terN
 	{
 		if(elem.first->ID == Obj::HOLE) //Hole
 		{
-			out = elem.first->hoverName;
+			out = elem.first->getObjectName();
 			return;
 		}
 	}
@@ -1092,3 +1081,25 @@ ui8 CMapHandler::getPhaseShift(const CGObjectInstance *object) const
 TerrainTile2::TerrainTile2()
  :terbitmap(nullptr)
 {}
+
+bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObjectInstance * b)
+{
+	if (a->appearance.printPriority != b->appearance.printPriority)
+		return a->appearance.printPriority > b->appearance.printPriority;
+
+	if(a->pos.y != b->pos.y)
+		return a->pos.y < b->pos.y;
+
+	if(b->ID==Obj::HERO && a->ID!=Obj::HERO)
+		return true;
+	if(b->ID!=Obj::HERO && a->ID==Obj::HERO)
+		return false;
+
+	if(!a->isVisitable() && b->isVisitable())
+		return true;
+	if(!b->isVisitable() && a->isVisitable())
+		return false;
+	if(a->pos.x < b->pos.x)
+		return true;
+	return false;
+}

+ 2 - 1
client/mapHandler.h

@@ -108,7 +108,6 @@ public:
 	std::pair<SDL_Surface *, bool> getVisBitmap(const int3 & pos, const std::vector< std::vector< std::vector<ui8> > > & visibilityMap) const; //returns appropriate bitmap and info if alpha blitting is necessary
 	ui8 getPhaseShift(const CGObjectInstance *object) const;
 
-	std::vector< std::string > getObjDescriptions(int3 pos); //returns desriptions of objects blocking given position
 	void getTerrainDescr(const int3 &pos, std::string & out, bool terName); //if tername == false => empty string when tile is clear
 	CGObjectInstance * createObject(int id, int subid, int3 pos, int owner=254); //creates a new object with a certain id and subid
 	bool printObject(const CGObjectInstance * obj); //puts appropriate things to ttiles, so obj will be visible on map
@@ -127,4 +126,6 @@ public:
 	void validateRectTerr(SDL_Rect * val, const SDL_Rect * ext); //terrainRect helper
 	static ui8 getDir(const int3 & a, const int3 & b);  //returns direction number in range 0 - 7 (0 is left top, clockwise) [direction: form a to b]
 
+	static bool compareObjectBlitOrder(const CGObjectInstance * a, const CGObjectInstance * b);
+
 };

+ 118 - 99
config/objects/generic.json

@@ -8,126 +8,145 @@
 			"prison" : { "index" : 0 }
 		}
 	},
-	
-	"altarOfSacrifice"				: { "index" :2,  "handler": "market" },
-	"tradingPost"					: { "index" :221, "handler": "market" },
-	"tradingPostDUPLICATE"			: { "index" :99, "handler": "market" },
-	"freelancersGuild"				: { "index" :213, "handler": "market" },
 
-	"blackMarket"					: { "index" :7,  "handler": "blackMarket" },
+	"altarOfSacrifice"				: { "index" :2,   "handler": "market", "types" : { "object" : { "index" : 0} } },
+	"tradingPost"					: { "index" :221, "handler": "market", "types" : { "object" : { "index" : 0} } },
+	"tradingPostDUPLICATE"			: { "index" :99,  "handler": "market", "types" : { "object" : { "index" : 0} } },
+	"freelancersGuild"				: { "index" :213, "handler": "market", "types" : { "object" : { "index" : 0} } },
+
+	"blackMarket"					: { "index" :7,   "handler": "blackMarket", "types" : { "object" : { "index" : 0} } },
 
-	"pandoraBox"					: { "index" :6,  "handler": "pandora" },
-	"event"							: { "index" :26, "handler": "event" },
+	"pandoraBox"					: { "index" :6,   "handler": "pandora", "types" : { "object" : { "index" : 0} } },
+	"event"							: { "index" :26,  "handler": "event", "types" : { "object" : { "index" : 0} } },
 
-	"redwoodObservatory"			: { "index" :58, "handler": "observatory" },
-	"pillarOfFire"					: { "index" :60, "handler": "observatory" },
-	"coverOfDarkness"				: { "index" :15, "handler": "observatory" },
+	"redwoodObservatory"			: { "index" :58,  "handler": "observatory", "types" : { "object" : { "index" : 0} } },
+	"pillarOfFire"					: { "index" :60,  "handler": "observatory", "types" : { "object" : { "index" : 0} } },
+	"coverOfDarkness"				: { "index" :15,  "handler": "observatory", "types" : { "object" : { "index" : 0} } },
 	
-	"subterraneanGate"				: { "index" :103, "handler": "teleport" },
-	"whirlpool"						: { "index" :111, "handler": "teleport" },
+	"whirlpool"						: { "index" :111, "handler": "teleport", "types" : { "object" : { "index" : 0} } },
+	"subterraneanGate" : {
+		"index" :103,
+		"handler": "teleport",
+		"types" : {
+			"object" : { "index" : 0 },
+			"objectWoG" : { "index" : 1 } // WoG object? Present on VCMI Test 2011b
+		}
+	},
 
-	"refugeeCamp"					: { "index" :78, "handler": "dwelling" },
-	"warMachineFactory"				: { "index" :106, "handler": "dwelling" },
+	"refugeeCamp"					: { "index" :78,  "handler": "dwelling", "types" : { "object" : { "index" : 0} } },
+	"warMachineFactory"				: { "index" :106, "handler": "dwelling", "types" : { "object" : { "index" : 0} } },
 
-	"shrineOfMagicLevel1"			: { "index" :88, "handler": "shrine" },
-	"shrineOfMagicLevel2"			: { "index" :89, "handler": "shrine" },
-	"shrineOfMagicLevel3"			: { "index" :90, "handler": "shrine" },
+	"shrineOfMagicLevel1"			: { "index" :88,  "handler": "shrine", "types" : { "object" : { "index" : 0} } },
+	"shrineOfMagicLevel2"			: { "index" :89,  "handler": "shrine", "types" : { "object" : { "index" : 0} } },
+	"shrineOfMagicLevel3"			: { "index" :90,  "handler": "shrine", "types" : { "object" : { "index" : 0} } },
 
-	"eyeOfTheMagi"					: { "index" :27, "handler": "magi" },
-	"hutOfTheMagi"					: { "index" :37, "handler": "magi" },
+	"eyeOfTheMagi"					: { "index" :27,  "handler": "magi", "types" : { "object" : { "index" : 0} } },
+	"hutOfTheMagi"					: { "index" :37,  "handler": "magi", "types" : { "object" : { "index" : 0} } },
 
-	"lighthouse"					: { "index" :42, "handler": "lighthouse" },
-	"magicWell"						: { "index" :49, "handler": "magicWell" },
-	"obelisk"						: { "index" :57, "handler": "obelisk" },
-	"oceanBottle"					: { "index" :59, "handler": "sign" },
-	"scholar"						: { "index" :81, "handler": "scholar" },
-	"shipyard"						: { "index" :87, "handler": "shipyard" },
-	"sign"							: { "index" :91, "handler": "sign" },
-	"sirens"						: { "index" :92, "handler": "siren" },
-	"denOfThieves"					: { "index" :97, "handler": "denOfThieves" },
-	"university"					: { "index" :104, "handler": "university" },
-	"witchHut"						: { "index" :113, "handler": "witch" },
-	"questGuard"					: { "index" :215, "handler": "questGuard" },
+	"lighthouse"					: { "index" :42,  "handler": "lighthouse", "types" : { "object" : { "index" : 0} } },
+	"obelisk"						: { "index" :57,  "handler": "obelisk", "types" : { "object" : { "index" : 0} } },
+	"oceanBottle"					: { "index" :59,  "handler": "sign", "types" : { "object" : { "index" : 0} } },
+	"scholar"						: { "index" :81,  "handler": "scholar", "types" : { "object" : { "index" : 0} } },
+	"shipyard"						: { "index" :87,  "handler": "shipyard", "types" : { "object" : { "index" : 0} } },
+	"sign"							: { "index" :91,  "handler": "sign", "types" : { "object" : { "index" : 0} } },
+	"sirens"						: { "index" :92,  "handler": "siren", "types" : { "object" : { "index" : 0} } },
+	"denOfThieves"					: { "index" :97,  "handler": "denOfThieves", "types" : { "object" : { "index" : 0} } },
+	"university"					: { "index" :104, "handler": "university", "types" : { "object" : { "index" : 0} } },
+	"witchHut"						: { "index" :113, "handler": "witch", "types" : { "object" : { "index" : 0} } },
+	"questGuard"					: { "index" :215, "handler": "questGuard", "types" : { "object" : { "index" : 0} } },
+	"magicWell" : {
+		"index" :49,
+		"handler": "magicWell",
+		"types" : {
+			"object" : { "index" : 0},
+			"objectWoG" : { "index" : 1} // WoG object? Present on VCMI_Test 2011b
+		}
+	},
 
 	/// Random objects
-	"randomResource"				: { "index" :76, "handler": "resource" },
-	"randomTown"					: { "index" :77, "handler": "town" },
-	"randomHero"					: { "index" :70, "handler": "hero" },
+	"randomResource"				: { "index" :76,  "handler": "resource" },
+	"randomTown"					: { "index" :77,  "handler": "town" },
+	"randomHero"					: { "index" :70,  "handler": "hero" },
 	
 	"randomDwelling"				: { "index" :216, "handler": "dwelling" },
 
-	"randomArtifact"				: { "index" :65, "handler": "artifact" },
-	"randomArtifactTreasure"		: { "index" :66, "handler": "artifact" },
-	"randomArtifactMinor"			: { "index" :67, "handler": "artifact" },
-	"randomArtifactMajor"			: { "index" :68, "handler": "artifact" },
-	"randomArtifactRelic"			: { "index" :69, "handler": "artifact" },
+	"randomArtifact"				: { "index" :65,  "handler": "artifact" },
+	"randomArtifactTreasure"		: { "index" :66,  "handler": "artifact" },
+	"randomArtifactMinor"			: { "index" :67,  "handler": "artifact" },
+	"randomArtifactMajor"			: { "index" :68,  "handler": "artifact" },
+	"randomArtifactRelic"			: { "index" :69,  "handler": "artifact" },
 
-	"randomMonster"					: { "index" :71, "handler": "monster" },
-	"randomMonsterLevel1"			: { "index" :72, "handler": "monster" },
-	"randomMonsterLevel2"			: { "index" :73, "handler": "monster" },
-	"randomMonsterLevel3"			: { "index" :74, "handler": "monster" },
-	"randomMonsterLevel4"			: { "index" :75, "handler": "monster" },
+	"randomMonster"					: { "index" :71,  "handler": "monster" },
+	"randomMonsterLevel1"			: { "index" :72,  "handler": "monster" },
+	"randomMonsterLevel2"			: { "index" :73,  "handler": "monster" },
+	"randomMonsterLevel3"			: { "index" :74,  "handler": "monster" },
+	"randomMonsterLevel4"			: { "index" :75,  "handler": "monster" },
 	"randomMonsterLevel5"			: { "index" :162, "handler": "monster" },
 	"randomMonsterLevel6"			: { "index" :163, "handler": "monster" },
 	"randomMonsterLevel7"			: { "index" :164, "handler": "monster" },
 
 	/// Classes without dedicated object
-	"hillFort"						: { "index" :35, "handler": "generic" },
-	"grail"							: { "index" :36, "handler": "generic" },
-	"tavern"						: { "index" :95, "handler": "generic" },
-	"sanctuary"						: { "index" :80, "handler": "generic" },
+	"hillFort"						: { "index" :35,  "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"grail"							: { "index" :36,  "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"tavern"						: { "index" :95,  "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"sanctuary"						: { "index" :80,  "handler": "generic", "types" : { "object" : { "index" : 0} } },
 
 	/// Passive objects, terrain overlays
-	"cursedGround"					: { "index" :21, "handler": "generic" },
-	"magicPlains"					: { "index" :46, "handler": "generic" },
-	"swampFoliage"					: { "index" :211, "handler": "generic" },
-	"cloverField"					: { "index" :222, "handler": "generic" },
-	"cursedGroundDUPLICATE"			: { "index" :223, "handler": "generic" },
-	"evilFog"						: { "index" :224, "handler": "generic" },
-	"favorableWinds"				: { "index" :225, "handler": "generic" },
-	"fieryFields"					: { "index" :226, "handler": "generic" },
-	"holyGround"					: { "index" :227, "handler": "generic" },
-	"lucidPools"					: { "index" :228, "handler": "generic" },
-	"magicClouds"					: { "index" :229, "handler": "generic" },
-	"magicPlainsDUPLICATE"			: { "index" :230, "handler": "generic" },
-	"rocklands"						: { "index" :231, "handler": "generic" },
+	"cursedGround"					: { "index" :21,  "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"magicPlains"					: { "index" :46,  "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"swampFoliage"					: { "index" :211, "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"cloverField"					: { "index" :222, "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"cursedGroundDUPLICATE"			: { "index" :223, "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"evilFog"						: { "index" :224, "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"favorableWinds"				: { "index" :225, "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"fieryFields"					: { "index" :226, "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"holyGround"					: { "index" :227, "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"lucidPools"					: { "index" :228, "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"magicClouds"					: { "index" :229, "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"magicPlainsDUPLICATE"			: { "index" :230, "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"rocklands"						: { "index" :231, "handler": "generic", "types" : { "object" : { "index" : 0} } },
 
 	/// Decorations
-	"cactus"						: { "index" :116, "handler": "static" },
-	"canyon"						: { "index" :117, "handler": "static" },
-	"crater"						: { "index" :118, "handler": "static" },
-	"deadVegetation"				: { "index" :119, "handler": "static" },
-	"flowers"						: { "index" :120, "handler": "static" },
-	"frozenLake"					: { "index" :121, "handler": "static" },
-	"hole"							: { "index" :124, "handler": "static" },
-	"kelp"							: { "index" :125, "handler": "static" },
-	"lake"							: { "index" :126, "handler": "static" },
-	"lavaFlow"						: { "index" :127, "handler": "static" },
-	"lavaLake"						: { "index" :128, "handler": "static" },
-	"mushrooms"						: { "index" :129, "handler": "static" },
-	"log"							: { "index" :130, "handler": "static" },
-	"mandrake"						: { "index" :131, "handler": "static" },
-	"moss"							: { "index" :132, "handler": "static" },
-	"mound"							: { "index" :133, "handler": "static" },
-	"mountain"						: { "index" :134, "handler": "static" },
-	"oakTrees"						: { "index" :135, "handler": "static" },
-	"outcropping"					: { "index" :136, "handler": "static" },
-	"pineTrees"						: { "index" :137, "handler": "static" },
-	"riverDelta"					: { "index" :143, "handler": "static" },
-	"rock"							: { "index" :147, "handler": "static" },
-	"sandDune"						: { "index" :148, "handler": "static" },
-	"sandPit"						: { "index" :149, "handler": "static" },
-	"shrub"							: { "index" :150, "handler": "static" },
-	"skull"							: { "index" :151, "handler": "static" },
-	"stump"							: { "index" :153, "handler": "static" },
-	"trees"							: { "index" :155, "handler": "static" },
-	"volcano"						: { "index" :158, "handler": "static" },
-	"reef"							: { "index" :161, "handler": "static" },
-	"lakeDUPLICATE"					: { "index" :177, "handler": "static" },
-	"treesDUPLICATE"				: { "index" :199, "handler": "static" },
-	"desertHills"					: { "index" :206, "handler": "static" },
-	"dirtHills"						: { "index" :207, "handler": "static" },
-	"grassHills"					: { "index" :208, "handler": "static" },
-	"roughHills"					: { "index" :209, "handler": "static" },
-	"subterraneanRocks"				: { "index" :210, "handler": "static" }
+	"cactus"						: { "index" :116, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"canyon"						: { "index" :117, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"crater"						: { "index" :118, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"deadVegetation"				: { "index" :119, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"flowers"						: { "index" :120, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"frozenLake"					: { "index" :121, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"hole"							: { "index" :124, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"kelp"							: { "index" :125, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"lake"							: { "index" :126, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"lavaFlow"						: { "index" :127, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"lavaLake"						: { "index" :128, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"mushrooms"						: { "index" :129, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"log"							: { "index" :130, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"mandrake"						: { "index" :131, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"moss"							: { "index" :132, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"mound"							: { "index" :133, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"mountain"						: { "index" :134, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"oakTrees"						: { "index" :135, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"outcropping"					: { "index" :136, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"pineTrees"						: { "index" :137, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"riverDelta"					: { "index" :143, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"rock"							: { "index" :147, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"sandDune"						: { "index" :148, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"sandPit"						: { "index" :149, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"shrub"							: { "index" :150, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"skull"							: { "index" :151, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"stump"							: { "index" :153, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"trees"							: { "index" :155, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"volcano"						: { "index" :158, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"reef"							: { "index" :161, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"lakeDUPLICATE"					: { "index" :177, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"treesDUPLICATE"				: { "index" :199, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"desertHills"					: { "index" :206, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"dirtHills"						: { "index" :207, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"grassHills"					: { "index" :208, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"roughHills"					: { "index" :209, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"subterraneanRocks"				: { "index" :210, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	
+	//These are WoG objects? They are not available in H3
+	"frozenLakeDUPLICATE"			: { "index" :172, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"oakTreesDUPLICATE"				: { "index" :186, "handler": "static", "types" : { "object" : { "index" : 0} } },
+	"plant"							: { "index" :189, "handler": "static", "types" : { "object" : { "index" : 0} } }
 }

+ 42 - 3
config/objects/moddables.json

@@ -189,9 +189,48 @@
 	"garrisonVertical"				: { "index" :219, "handler": "garrison" },
 
 	// Subtype: paired monoliths
-	"monolithOneWayEntrance"		: { "index" :43, "handler": "teleport" },
-	"monolithOneWayExit"			: { "index" :44, "handler": "teleport" },
-	"monolithTwoWay"				: { "index" :45, "handler": "teleport" },
+	"monolithOneWayEntrance" : {
+		"index" :43,
+		"handler": "teleport",
+		"types" : {
+			"monolith1" : { "index" : 0 },
+			"monolith2" : { "index" : 1 },
+			"monolith3" : { "index" : 2 },
+			"monolith4" : { "index" : 3 },
+			"monolith5" : { "index" : 4 },
+			"monolith6" : { "index" : 5 },
+			"monolith7" : { "index" : 6 },
+			"monolith8" : { "index" : 7 }
+		}
+	},
+	"monolithOneWayExit" : {
+		"index" :44,
+		"handler": "teleport",
+		"types" : {
+			"monolith1" : { "index" : 0 },
+			"monolith2" : { "index" : 1 },
+			"monolith3" : { "index" : 2 },
+			"monolith4" : { "index" : 3 },
+			"monolith5" : { "index" : 4 },
+			"monolith6" : { "index" : 5 },
+			"monolith7" : { "index" : 6 },
+			"monolith8" : { "index" : 7 }
+		}
+	},
+	"monolithTwoWay" : {
+		"index" :45,
+		"handler": "teleport",
+		"types" : {
+			"monolith1" : { "index" : 0 },
+			"monolith2" : { "index" : 1 },
+			"monolith3" : { "index" : 2 },
+			"monolith4" : { "index" : 3 },
+			"monolith5" : { "index" : 4 },
+			"monolith6" : { "index" : 5 },
+			"monolith7" : { "index" : 6 },
+			"monolith8" : { "index" : 7 }
+		}
+	},
 
 	// subtype: different appearance. That's all?
 	"seerHut" : { "index" :83, "handler": "seerHut" },

+ 43 - 36
config/objects/rewardable.json

@@ -1,44 +1,51 @@
 {
 	/// These are objects that covered by concept of "configurable object"
 	/// Most or even all of their configuration located in this file
-	"magicSpring"					: { "index" :48, "handler": "magicSpring" },
+	"magicSpring"					: { "index" :48, "handler": "magicSpring", "types" : { "object" : { "index" : 0} } },
 
-	"mysticalGarden"				: { "index" :55, "handler": "oncePerWeek" },
-	"windmill"						: { "index" :112, "handler": "oncePerWeek" },
-	"waterWheel"					: { "index" :109, "handler": "oncePerWeek" },
+	"mysticalGarden"				: { "index" :55, "handler": "oncePerWeek", "types" : { "object" : { "index" : 0} } },
+	"windmill"						: { "index" :112, "handler": "oncePerWeek", "types" : { "object" : { "index" : 0} } },
+	"waterWheel"					: { "index" :109, "handler": "oncePerWeek", "types" : { "object" : { "index" : 0} } },
 	
-	"leanTo"						: { "index" :39, "handler": "onceVisitable" },
-	"corpse"						: { "index" :22, "handler": "onceVisitable" },
-	"wagon"							: { "index" :105, "handler": "onceVisitable" },
-	"warriorTomb"					: { "index" :108, "handler": "onceVisitable" },
+	"leanTo"						: { "index" :39, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } },
+	"corpse"						: { "index" :22, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } },
+	"wagon"							: { "index" :105, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } },
+	"warriorTomb"					: { "index" :108, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } },
 
-	"campfire"						: { "index" :12, "handler": "pickable" },
-	"flotsam"						: { "index" :29, "handler": "pickable" },
-	"seaChest"						: { "index" :82, "handler": "pickable" },
-	"shipwreckSurvivor"				: { "index" :86, "handler": "pickable" },
-	"treasureChest"					: { "index" :101, "handler": "pickable" },
+	"campfire"						: { "index" :12, "handler": "pickable", "types" : { "object" : { "index" : 0} } },
+	"flotsam"						: { "index" :29, "handler": "pickable", "types" : { "object" : { "index" : 0} } },
+	"seaChest"						: { "index" :82, "handler": "pickable", "types" : { "object" : { "index" : 0} } },
+	"shipwreckSurvivor"				: { "index" :86, "handler": "pickable", "types" : { "object" : { "index" : 0} } },
+	"treasureChest"					: { "index" :101, "handler": "pickable", "types" : { "object" : { "index" : 0} } },
 
-	"arena"							: { "index" :4,  "handler": "oncePerHero" },
-	"marlettoTower"					: { "index" :23, "handler": "oncePerHero" },
-	"gardenOfRevelation"			: { "index" :32, "handler": "oncePerHero" },
-	"libraryOfEnlightenment"		: { "index" :41, "handler": "oncePerHero" },
-	"mercenaryCamp"					: { "index" :51, "handler": "oncePerHero" },
-	"starAxis"						: { "index" :61, "handler": "oncePerHero" },
-	"learningStone"					: { "index" :100, "handler": "oncePerHero" },
-	"treeOfKnowledge"				: { "index" :102, "handler": "oncePerHero" },
-	"schoolOfMagic"					: { "index" :47, "handler": "oncePerHero" },
-	"schoolOfWar"					: { "index" :107, "handler": "oncePerHero" },
-	
-	"buoy"							: { "index" :11, "handler": "bonusingObject" },
-	"swanPond"						: { "index" :14, "handler": "bonusingObject" },
-	"faerieRing"					: { "index" :28, "handler": "bonusingObject" },
-	"fountainOfFortune"				: { "index" :30, "handler": "bonusingObject" },
-	"fountainOfYouth"				: { "index" :31, "handler": "bonusingObject" },
-	"idolOfFortune"					: { "index" :38, "handler": "bonusingObject" },
-	"mermaids"						: { "index" :52, "handler": "bonusingObject" },
-	"oasis"							: { "index" :56, "handler": "bonusingObject" },
-	"stables"						: { "index" :94, "handler": "bonusingObject" },
-	"temple"						: { "index" :96, "handler": "bonusingObject" },
-	"rallyFlag"						: { "index" :64, "handler": "bonusingObject" },
-	"wateringHole"					: { "index" :110, "handler": "bonusingObject" },	
+	"arena"							: { "index" :4,  "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
+	"marlettoTower"					: { "index" :23, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
+	"gardenOfRevelation"			: { "index" :32, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
+	"libraryOfEnlightenment"		: { "index" :41, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
+	"mercenaryCamp"					: { "index" :51, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
+	"starAxis"						: { "index" :61, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
+	"treeOfKnowledge"				: { "index" :102, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
+	"schoolOfMagic"					: { "index" :47, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
+	"schoolOfWar"					: { "index" :107, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
+	"learningStone" : {
+		"index" :100,
+		"handler": "oncePerHero",
+		"types" : {
+			"object" : { "index" : 0},
+			"objectWoG" : { "index" : 1} // WoG object? Present on VCMI_Tests 2011
+		}
+	},
+
+	"buoy"							: { "index" :11, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
+	"swanPond"						: { "index" :14, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
+	"faerieRing"					: { "index" :28, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
+	"fountainOfFortune"				: { "index" :30, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
+	"fountainOfYouth"				: { "index" :31, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
+	"idolOfFortune"					: { "index" :38, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
+	"mermaids"						: { "index" :52, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
+	"oasis"							: { "index" :56, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
+	"stables"						: { "index" :94, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
+	"temple"						: { "index" :96, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
+	"rallyFlag"						: { "index" :64, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
+	"wateringHole"					: { "index" :110, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }
 }

+ 5 - 0
config/schemas/mod.json

@@ -87,6 +87,11 @@
 			"description": "List of configuration files for heroes",
 			"items": { "type":"string", "format" : "textFile" }
 		},
+		"objects": {
+			"type":"array",
+			"description": "List of configuration files for objects",
+			"items": { "type":"string", "format" : "textFile" }
+		},
 		"spells": {
 			"type":"array",
 			"description": "List of configuration files for spells",

+ 2 - 4
lib/BattleState.cpp

@@ -365,13 +365,11 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp
 	if(town)
 	{
 		curB->town = town;
-		curB->siege = town->fortLevel();
 		curB->terrainType = VLC->townh->factions[town->subID]->nativeTerrain;
 	}
 	else
 	{
 		curB->town = nullptr;
-		curB->siege = CGTownInstance::NONE;
 		curB->terrainType = terrain;
 	}
 
@@ -574,13 +572,13 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp
 
 	}
 
-	if (curB->siege == CGTownInstance::CITADEL || curB->siege == CGTownInstance::CASTLE)
+	if (curB->town && curB->town->fortLevel() >= CGTownInstance::CITADEL)
 	{
 		// keep tower
 		CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID(255), -2);
 		stacks.push_back(stack);
 
-		if (curB->siege == CGTownInstance::CASTLE)
+		if (curB->town->fortLevel() >= CGTownInstance::CASTLE)
 		{
 			// lower tower + upper tower
 			CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID(255), -4);

+ 4 - 5
lib/BattleState.h

@@ -4,8 +4,8 @@
 #include "BattleHex.h"
 #include "HeroBonus.h"
 #include "CCreatureSet.h"
-#include "mapObjects/CGTownInstance.h"
-#include "mapObjects/CGHeroInstance.h"
+#include "mapObjects/CArmedInstance.h" // for army serialization
+#include "mapObjects/CGHeroInstance.h" // for commander serialization
 #include "CCreatureHandler.h"
 #include "CObstacleInstance.h"
 #include "ConstTransitivePtr.h"
@@ -83,8 +83,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
 {
 	std::array<SideInBattle, 2> sides; //sides[0] - attacker, sides[1] - defender
 	si32 round, activeStack, selectedStack;
-	CGTownInstance::EFortLevel siege;
-	const CGTownInstance * town; //used during town siege - id of attacked town; -1 if not town defence
+	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;
@@ -99,7 +98,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & sides;
-		h & round & activeStack & selectedStack & siege & town & tile & stacks & obstacles
+		h & round & activeStack & selectedStack & town & tile & stacks & obstacles
 			& si & battlefieldType & terrainType;
 		h & tacticsSide & tacticDistance;
 		h & static_cast<CBonusSystemNode&>(*this);

+ 2 - 2
lib/CArtHandler.h

@@ -2,8 +2,8 @@
 
 
 #include "../lib/HeroBonus.h"
-#include "../lib/ConstTransitivePtr.h"
-#include "JsonNode.h"
+//#include "../lib/ConstTransitivePtr.h"
+//#include "JsonNode.h"
 #include "GameConstants.h"
 #include "IHandlerBase.h"
 

+ 2 - 2
lib/CBattleCallback.cpp

@@ -409,7 +409,7 @@ ui8 CBattleInfoEssentials::playerToSide(PlayerColor player) const
 ui8 CBattleInfoEssentials::battleGetSiegeLevel() const
 {
 	RETURN_IF_NOT_BATTLE(0);
-	return getBattle()->siege;
+	return getBattle()->town ? getBattle()->town->fortLevel() : CGTownInstance::NONE;
 }
 
 bool CBattleInfoEssentials::battleCanSurrender(PlayerColor player) const
@@ -429,7 +429,7 @@ bool CBattleInfoEssentials::battleHasHero(ui8 side) const
 si8 CBattleInfoEssentials::battleGetWallState(int partOfWall) const
 {
 	RETURN_IF_NOT_BATTLE(0);
-	if(getBattle()->siege == CGTownInstance::NONE)
+	if(getBattle()->town == nullptr || getBattle()->town->fortLevel() == CGTownInstance::NONE)
 		return EWallState::NONE;
 
 	assert(partOfWall >= 0 && partOfWall < EWallPart::PARTS_COUNT);

+ 1 - 0
lib/CCreatureSet.cpp

@@ -224,6 +224,7 @@ ui64 CCreatureSet::getPower (SlotID slot) const
 {
 	return getStack(slot).getPower();
 }
+
 std::string CCreatureSet::getRoughAmount (SlotID slot) const
 {
 	int quantity = CCreature::getQuantityID(getStackCount(slot));

+ 1 - 12
lib/CGameInfoCallback.cpp

@@ -16,6 +16,7 @@
 #include "StartInfo.h" // for StartInfo
 #include "BattleState.h" // for BattleInfo
 #include "NetPacks.h" // for InfoWindow
+#include "CModHandler.h"
 
 //TODO make clean
 #define ERROR_VERBOSE_OR_NOT_RET_VAL_IF(cond, verbose, txt, retVal) do {if(cond){if(verbose)logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0)
@@ -260,18 +261,6 @@ int CGameInfoCallback::getDate(Date::EDateType mode) const
 	//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	return gs->getDate(mode);
 }
-std::vector < std::string > CGameInfoCallback::getObjDescriptions(int3 pos) const
-{
-	//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
-	std::vector<std::string> ret;
-	const TerrainTile *t = getTile(pos);
-	ERROR_RET_VAL_IF(!t, "Not a valid tile given!", ret);
-
-
-	for(const CGObjectInstance * obj : t->blockingObjects)
-		ret.push_back(obj->getHoverText());
-	return ret;
-}
 
 bool CGameInfoCallback::isVisible(int3 pos, boost::optional<PlayerColor> Player) const
 {

+ 0 - 1
lib/CGameInfoCallback.h

@@ -83,7 +83,6 @@ public:
 	std::vector <const CGObjectInstance * > getVisitableObjs(int3 pos, bool verbose = true)const;
 	std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
 	const CGObjectInstance * getTopObj (int3 pos) const;
-	std::vector <std::string > getObjDescriptions(int3 pos)const; //returns descriptions of objects at pos in order from the lowest to the highest
 	PlayerColor getOwner(ObjectInstanceID heroID) const;
 	const CGObjectInstance *getObjByQuestIdentifier(int identifier) const; //nullptr if object has been removed (eg. killed)
 

+ 2 - 56
lib/CGameState.cpp

@@ -1053,7 +1053,6 @@ void CGameState::randomizeMapObjects()
 		if(!obj) continue;
 
 		randomizeObject(obj);
-		obj->hoverName = VLC->objtypeh->getObjectName(obj->ID);
 
 		//handle Favouring Winds - mark tiles under it
 		if(obj->ID == Obj::FAVORABLE_WINDS)
@@ -1637,7 +1636,7 @@ void CGameState::initFogOfWar()
 			if(!obj || !vstd::contains(elem.second.players, obj->tempOwner)) continue; //not a flagged object
 
 			std::unordered_set<int3, ShashInt3> tiles;
-			obj->getSightTiles(tiles);
+			getTilesInRange(tiles, obj->getSightCenter(), obj->getSightRadious(), obj->tempOwner, 1);
 			for(int3 tile : tiles)
 			{
 				elem.second.fogOfWarMap[tile.x][tile.y][tile.z] = 1;
@@ -2980,7 +2979,7 @@ void InfoAboutArmy::initFromArmy(const CArmedInstance *Army, bool detailed)
 {
 	army = ArmyDescriptor(Army, detailed);
 	owner = Army->tempOwner;
-	name = Army->getHoverText();
+	name = Army->getObjectName();
 }
 
 void InfoAboutHero::assign(const InfoAboutHero & iah)
@@ -3510,59 +3509,6 @@ CPathfinder::CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance
 	allowEmbarkAndDisembark = true;
 }
 
-EVictoryLossCheckResult::EVictoryLossCheckResult() :
-	intValue(0)
-{
-}
-
-EVictoryLossCheckResult::EVictoryLossCheckResult(si32 intValue, std::string toSelf, std::string toOthers) :
-	messageToSelf(toSelf),
-	messageToOthers(toOthers),
-	intValue(intValue)
-{
-}
-
-bool EVictoryLossCheckResult::operator==(EVictoryLossCheckResult const & other) const
-{
-	return intValue == other.intValue;
-}
-
-bool EVictoryLossCheckResult::operator!=(EVictoryLossCheckResult const & other) const
-{
-	return intValue != other.intValue;
-}
-
-bool EVictoryLossCheckResult::victory() const
-{
-	return intValue == VICTORY;
-}
-
-bool EVictoryLossCheckResult::loss() const
-{
-	return intValue == DEFEAT;
-}
-
-EVictoryLossCheckResult EVictoryLossCheckResult::invert()
-{
-	return EVictoryLossCheckResult(-intValue, messageToOthers, messageToSelf);
-}
-
-EVictoryLossCheckResult EVictoryLossCheckResult::victory(std::string toSelf, std::string toOthers)
-{
-	return EVictoryLossCheckResult(VICTORY, toSelf, toOthers);
-}
-
-EVictoryLossCheckResult EVictoryLossCheckResult::defeat(std::string toSelf, std::string toOthers)
-{
-	return EVictoryLossCheckResult(DEFEAT, toSelf, toOthers);
-}
-
-std::ostream & operator<<(std::ostream & os, const EVictoryLossCheckResult & victoryLossCheckResult)
-{
-	os << victoryLossCheckResult.messageToSelf;
-	return os;
-}
-
 CRandomGenerator & CGameState::getRandomGenerator()
 {
 	return rand;

+ 1 - 65
lib/CGameState.h

@@ -15,6 +15,7 @@
 #include "ResourceSet.h"
 #include "int3.h"
 #include "CRandomGenerator.h"
+#include "CGameStateFwd.h"
 
 /*
  * CGameState.h, part of VCMI engine
@@ -355,39 +356,6 @@ public:
 
 struct BattleInfo;
 
-class DLL_LINKAGE EVictoryLossCheckResult
-{
-public:
-	static EVictoryLossCheckResult victory(std::string toSelf, std::string toOthers);
-	static EVictoryLossCheckResult defeat(std::string toSelf, std::string toOthers);
-
-	EVictoryLossCheckResult();
-	bool operator==(EVictoryLossCheckResult const & other) const;
-	bool operator!=(EVictoryLossCheckResult const & other) const;
-	bool victory() const;
-	bool loss() const;
-
-	EVictoryLossCheckResult invert();
-
-	std::string messageToSelf;
-	std::string messageToOthers;
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & intValue & messageToSelf & messageToOthers;
-	}
-private:
-	enum EResult
-	{
-		DEFEAT = -1,
-		INGAME =  0,
-		VICTORY= +1
-	};
-
-	EVictoryLossCheckResult(si32 intValue, std::string toSelf, std::string toOthers);
-	si32 intValue; // uses EResult
-};
-
 DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const EVictoryLossCheckResult & victoryLossCheckResult);
 
 class DLL_LINKAGE CGameState : public CNonConstInfoCallback
@@ -533,35 +501,3 @@ private:
 	friend class CMapHandler;
 	friend class CGameHandler;
 };
-
-struct DLL_LINKAGE QuestInfo //universal interface for human and AI
-{
-	const CQuest * quest;
-	const CGObjectInstance * obj; //related object, most likely Seer Hut
-	int3 tile;
-
-	QuestInfo(){};
-	QuestInfo (const CQuest * Quest, const CGObjectInstance * Obj, int3 Tile) :
-		quest (Quest), obj (Obj), tile (Tile){};
-
-	//FIXME: assignment operator should return QuestInfo &
-	bool operator= (const QuestInfo &qi)
-	{
-		quest = qi.quest;
-		obj = qi.obj;
-		tile = qi.tile;
-		return true;
-	}
-
-	bool operator== (const QuestInfo & qi) const
-	{
-		return (quest == qi.quest && obj == qi.obj);
-	}
-
-	//std::vector<std::string> > texts //allow additional info for quest log?
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & quest & obj & tile;
-	}
-};

+ 120 - 0
lib/CGameStateFwd.h

@@ -0,0 +1,120 @@
+#pragma once
+
+/*
+ * CGameStateFwd.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+class CQuest;
+class CGObjectInstance;
+
+class DLL_LINKAGE EVictoryLossCheckResult
+{
+public:
+	static EVictoryLossCheckResult victory(std::string toSelf, std::string toOthers)
+	{
+		return EVictoryLossCheckResult(VICTORY, toSelf, toOthers);
+	}
+
+	static EVictoryLossCheckResult defeat(std::string toSelf, std::string toOthers)
+	{
+		return EVictoryLossCheckResult(DEFEAT, toSelf, toOthers);
+	}
+
+	EVictoryLossCheckResult():
+	intValue(0)
+	{
+	}
+
+	bool operator==(EVictoryLossCheckResult const & other) const
+	{
+		return intValue == other.intValue;
+	}
+
+	bool operator!=(EVictoryLossCheckResult const & other) const
+	{
+		return intValue != other.intValue;
+	}
+
+	bool victory() const
+	{
+		return intValue == VICTORY;
+	}
+	bool loss() const
+	{
+		return intValue == DEFEAT;
+	}
+
+	EVictoryLossCheckResult invert()
+	{
+		return EVictoryLossCheckResult(-intValue, messageToOthers, messageToSelf);
+	}
+
+	std::string messageToSelf;
+	std::string messageToOthers;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & intValue & messageToSelf & messageToOthers;
+	}
+private:
+	enum EResult
+	{
+		DEFEAT = -1,
+		INGAME =  0,
+		VICTORY= +1
+	};
+
+	EVictoryLossCheckResult(si32 intValue, std::string toSelf, std::string toOthers):
+		messageToSelf(toSelf),
+		messageToOthers(toOthers),
+		intValue(intValue)
+	{
+	}
+
+	si32 intValue; // uses EResult
+};
+
+/*static std::ostream & operator<<(std::ostream & os, const EVictoryLossCheckResult & victoryLossCheckResult)
+{
+	os << victoryLossCheckResult.messageToSelf;
+	return os;
+}*/
+
+struct DLL_LINKAGE QuestInfo //universal interface for human and AI
+{
+	const CQuest * quest;
+	const CGObjectInstance * obj; //related object, most likely Seer Hut
+	int3 tile;
+
+	QuestInfo(){};
+	QuestInfo (const CQuest * Quest, const CGObjectInstance * Obj, int3 Tile) :
+		quest (Quest), obj (Obj), tile (Tile){};
+
+	//FIXME: assignment operator should return QuestInfo &
+	bool operator= (const QuestInfo &qi)
+	{
+		quest = qi.quest;
+		obj = qi.obj;
+		tile = qi.tile;
+		return true;
+	}
+
+	bool operator== (const QuestInfo & qi) const
+	{
+		return (quest == qi.quest && obj == qi.obj);
+	}
+
+	//std::vector<std::string> > texts //allow additional info for quest log?
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & quest & obj & tile;
+	}
+};
+

+ 2 - 1
lib/CMakeLists.txt

@@ -82,6 +82,7 @@ set(lib_SRCS
 		ResourceSet.cpp
 		VCMI_Lib.cpp
 		VCMIDirs.cpp
+		IHandlerBase.cpp
 
 		IGameCallback.cpp
 		CGameInfoCallback.cpp
@@ -118,8 +119,8 @@ set(lib_HEADERS
 		GameConstants.h
 		StringConstants.h
 		IGameEventsReceiver.h
-		IHandlerBase.h
 		int3.h
+		CGameStateFwd.h
 		Interprocess.h
 		NetPacks.h
 		NetPacksBase.h

+ 3 - 0
lib/IGameCallback.cpp

@@ -15,9 +15,12 @@
 #include "CSpellHandler.h" // for CSpell
 #include "NetPacks.h"
 #include "CBonusTypeHandler.h"
+#include "CModHandler.h"
 
 #include "Connection.h" // for SAVEGAME_MAGIC
 #include "mapObjects/CObjectClassesHandler.h"
+#include "StartInfo.h"
+#include "CGameState.h"
 
 void CPrivilagedInfoCallback::getFreeTiles (std::vector<int3> &tiles) const
 {

+ 2 - 1
lib/IGameCallback.h

@@ -48,7 +48,6 @@ public:
 	virtual bool removeObject(const CGObjectInstance * obj)=0;
 	virtual void setBlockVis(ObjectInstanceID objid, bool bv)=0;
 	virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0;
-	virtual void setHoverName(const CGObjectInstance * obj, MetaString * name)=0;
 	virtual void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false)=0;
 	virtual void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false)=0; 
 	virtual void showBlockingDialog(BlockingDialog *iw) =0;
@@ -93,6 +92,8 @@ public:
 	virtual void sendAndApply(CPackForClient * info)=0;
 	virtual void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)=0; //when two heroes meet on adventure map
 	virtual void addQuest(int player, QuestInfo & quest){};
+	virtual void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) = 0;
+	virtual void changeFogOfWar(std::unordered_set<int3, ShashInt3> &tiles, PlayerColor player, bool hide) = 0;
 };
 
 class DLL_LINKAGE CNonConstInfoCallback : public CPrivilagedInfoCallback

+ 19 - 0
lib/IHandlerBase.cpp

@@ -0,0 +1,19 @@
+/*
+ * IHandlerBase.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "StdInc.h"
+#include "IHandlerBase.h"
+#include "CModHandler.h"
+
+
+void IHandlerBase::registerObject(std::string scope, std::string type_name, std::string name, si32 index)
+{
+	return VLC->modh->identifiers.registerObject(scope, type_name, name, index);
+}

+ 6 - 4
lib/IHandlerBase.h

@@ -11,7 +11,7 @@
  */
  #include "../lib/ConstTransitivePtr.h"
  #include "VCMI_Lib.h"
- #include "CModHandler.h"
+ //#include "CModHandler.h"
 
 class JsonNode;
 
@@ -22,6 +22,9 @@ class DLL_LINKAGE IHandlerBase
 	// Object * loadFromJson(const JsonNode & json);
 	// where Object is type of data loaded by handler
 	// primary used in loadObject methods
+protected:
+	/// Calls modhandler. Mostly needed to avoid large number of includes in headers
+	void registerObject(std::string scope, std::string type_name, std::string name, si32 index);
 
 public:
 	/// loads all original game data in vector of json nodes
@@ -48,7 +51,6 @@ public:
 	virtual ~IHandlerBase(){}
 };
 
-
 template <class _ObjectID, class _Object> class CHandlerBase: public IHandlerBase
 {
 public:
@@ -68,7 +70,7 @@ public:
 
 		objects.push_back(object);
 
-		VLC->modh->identifiers.registerObject(scope, type_name, name, object->id);
+		registerObject(scope, type_name, name, object->id);
 	}
 	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override
 	{
@@ -80,7 +82,7 @@ public:
 		assert(objects[index] == nullptr); // ensure that this id was not loaded before
 		objects[index] = object;
 
-		VLC->modh->identifiers.registerObject(scope,type_name, name, object->id);
+		registerObject(scope,type_name, name, object->id);
 
 	}
 

+ 21 - 56
lib/NetPacks.h

@@ -3,16 +3,18 @@
 #include "NetPacksBase.h"
 
 #include "BattleAction.h"
-#include "HeroBonus.h"
+//#include "HeroBonus.h"
 #include "mapObjects/CGHeroInstance.h"
-#include "CCreatureSet.h"
-#include "mapping/CMapInfo.h"
-#include "StartInfo.h"
+//#include "CCreatureSet.h"
+//#include "mapping/CMapInfo.h"
+//#include "StartInfo.h"
 #include "ConstTransitivePtr.h"
 #include "int3.h"
 #include "ResourceSet.h"
+//#include "CObstacleInstance.h"
+#include "CGameStateFwd.h"
+#include "mapping/CMap.h"
 #include "CObstacleInstance.h"
-#include "CGameState.h"
 
 /*
  * NetPacks.h, part of VCMI engine
@@ -37,7 +39,8 @@ class CArtifactInstance;
 struct StackLocation;
 struct ArtSlotInfo;
 struct QuestInfo;
-
+class CMapInfo;
+class StartInfo;
 
 
 struct CPackForClient : public CPack
@@ -1045,21 +1048,6 @@ struct SetObjectProperty : public CPackForClient//1001
 	}
 };
 
-struct SetHoverName : public CPackForClient//1002
-{
-	DLL_LINKAGE void applyGs(CGameState *gs);
-
-	ObjectInstanceID id;
-	MetaString name;
-	SetHoverName(){type = 1002;}
-	SetHoverName(ObjectInstanceID ID, MetaString& Name):id(ID),name(Name){type = 1002;}
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & id & name;
-	}
-};
-
 struct ChangeObjectVisitors : public CPackForClient // 1003
 {
 	enum VisitMode
@@ -1527,7 +1515,8 @@ struct ObstaclesRemoved : public CPackForClient //3014
 	}
 };
 
-struct CatapultAttack : public CPackForClient //3015
+struct ELF_VISIBILITY CatapultAttack : public CPackForClient //3015
+
 {
 	struct AttackInfo
 	{
@@ -2136,26 +2125,14 @@ struct PlayerJoined : public CPregamePackToHost
 	}
 };
 
-struct SelectMap : public CPregamePackToPropagate
+struct ELF_VISIBILITY SelectMap : public CPregamePackToPropagate
 {
 	const CMapInfo *mapInfo;
-	bool free;
+	bool free;//local flag, do not serialize
 
-	SelectMap(const CMapInfo &src)
-	{
-		mapInfo = &src;
-		free = false;
-	}
-	SelectMap()
-	{
-		mapInfo = nullptr;
-		free = true;
-	}
-	~SelectMap()
-	{
-		if(free)
-			delete mapInfo;
-	}
+	DLL_LINKAGE SelectMap(const CMapInfo &src);
+	DLL_LINKAGE SelectMap();
+	DLL_LINKAGE ~SelectMap();
 
 	void apply(CSelectionScreen *selScreen); //that functions are implemented in CPreGame.cpp
 
@@ -2166,28 +2143,16 @@ struct SelectMap : public CPregamePackToPropagate
 
 };
 
-struct UpdateStartOptions : public CPregamePackToPropagate
+struct ELF_VISIBILITY UpdateStartOptions : public CPregamePackToPropagate
 {
 	StartInfo *options;
-	bool free;
+	bool free;//local flag, do not serialize
 
 	void apply(CSelectionScreen *selScreen); //that functions are implemented in CPreGame.cpp
 
-	UpdateStartOptions(StartInfo &src)
-	{
-		options = &src;
-		free = false;
-	}
-	UpdateStartOptions()
-	{
-		options = nullptr;
-		free = true;
-	}
-	~UpdateStartOptions()
-	{
-		if(free)
-			delete options;
-	}
+	DLL_LINKAGE UpdateStartOptions(StartInfo &src);
+	DLL_LINKAGE UpdateStartOptions();
+	DLL_LINKAGE ~UpdateStartOptions();
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 2 - 2
lib/NetPacksBase.h

@@ -25,7 +25,7 @@ struct ArtSlotInfo;
 #include "GameConstants.h"
 
 
-struct CPack
+struct DLL_LINKAGE CPack
 {
 	ui16 type;
 
@@ -197,4 +197,4 @@ struct ArtifactLocation
 	{
 		h & artHolder & slot;
 	}
-};
+};

+ 42 - 11
lib/NetPacksLib.cpp

@@ -14,6 +14,8 @@
 #include "CGameState.h"
 #include "BattleState.h"
 #include "CTownHandler.h"
+#include "mapping/CMapInfo.h"
+#include "StartInfo.h"
 
 /*
  * NetPacksLib.cpp, part of VCMI engine
@@ -60,6 +62,41 @@ DLL_LINKAGE void SetSecSkill::applyGs( CGameState *gs )
 	hero->setSecSkillLevel(which, val, abs);
 }
 
+
+DLL_LINKAGE SelectMap::SelectMap(const CMapInfo &src)
+{
+	mapInfo = &src;
+	free = false;
+}
+DLL_LINKAGE SelectMap::SelectMap()
+{
+	mapInfo = nullptr;
+	free = true;
+}
+
+DLL_LINKAGE SelectMap::~SelectMap()
+{
+	if(free)
+		delete mapInfo;
+}
+
+DLL_LINKAGE  UpdateStartOptions::UpdateStartOptions(StartInfo &src)
+{
+	options = &src;
+	free = false;
+}
+DLL_LINKAGE  UpdateStartOptions::UpdateStartOptions()
+{
+	options = nullptr;
+	free = true;
+}
+
+DLL_LINKAGE UpdateStartOptions::~UpdateStartOptions()
+{
+	if(free)
+		delete options;
+}
+
 DLL_LINKAGE void SetCommanderProperty::applyGs(CGameState *gs)
 {
 	CCommanderInstance * commander = gs->getHero(heroid)->commander;
@@ -177,7 +214,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
-						o->getSightTiles(tilesRevealed);
+						gs->getTilesInRange(tiles, o->getSightCenter(), o->getSightRadious(), o->tempOwner, 1);
 					break;
 				}
 			}
@@ -302,7 +339,7 @@ DLL_LINKAGE void RemoveObject::applyGs( CGameState *gs )
 {
 
 	CGObjectInstance *obj = gs->getObjInstance(id);
-	logGlobal->debugStream() << "removing object id=" << id << "; address=" << (intptr_t)obj << "; name=" << obj->getHoverText();
+	logGlobal->debugStream() << "removing object id=" << id << "; address=" << (intptr_t)obj << "; name=" << obj->getObjectName();
 	//unblock tiles
 	gs->map->removeBlockVisTiles(obj);
 
@@ -608,14 +645,13 @@ DLL_LINKAGE void NewObject::applyGs( CGameState *gs )
 	const TerrainTile &t = gs->map->getTile(pos);
 	o->appearance = VLC->objtypeh->getHandlerFor(o->ID, o->subID)->getTemplates(t.terType).front();
 	id = o->id = ObjectInstanceID(gs->map->objects.size());
-	o->hoverName = VLC->objtypeh->getObjectName(ID);
 
 	gs->map->objects.push_back(o);
 	gs->map->addBlockVisTiles(o);
 	o->initObj();
 	gs->map->calculateGuardingGreaturePositions();
 
-	logGlobal->debugStream() << "added object id=" << id << "; address=" << (intptr_t)o << "; name=" << o->getHoverText();
+	logGlobal->debugStream() << "added object id=" << id << "; address=" << (intptr_t)o << "; name=" << o->getObjectName();
 }
 
 DLL_LINKAGE void NewArtifact::applyGs( CGameState *gs )
@@ -1012,11 +1048,6 @@ DLL_LINKAGE void SetObjectProperty::applyGs( CGameState *gs )
 	}
 }
 
-DLL_LINKAGE void SetHoverName::applyGs( CGameState *gs )
-{
-	name.toString(gs->getObj(id)->hoverName);
-}
-
 DLL_LINKAGE void HeroLevelUp::applyGs( CGameState *gs )
 {
 	CGHeroInstance * h = gs->getHero(hero->id);
@@ -1495,6 +1526,7 @@ DLL_LINKAGE void ObstaclesRemoved::applyGs( CGameState *gs )
 	}
 }
 
+
 DLL_LINKAGE CatapultAttack::CatapultAttack()
 {
 	type = 3015;
@@ -1502,12 +1534,11 @@ DLL_LINKAGE CatapultAttack::CatapultAttack()
 
 DLL_LINKAGE CatapultAttack::~CatapultAttack()
 {
-
 }
 
 DLL_LINKAGE void CatapultAttack::applyGs( CGameState *gs )
 {
-	if(gs->curB && gs->curB->siege != CGTownInstance::NONE) //if there is a battle and it's a siege
+	if(gs->curB && gs->curB->town && gs->curB->town->fortLevel() != CGTownInstance::NONE) //if there is a battle and it's a siege
 	{
 		for(const auto &it :attackedParts)
 		{

+ 1 - 0
lib/VCMI_lib.cbp

@@ -128,6 +128,7 @@
 		<Unit filename="IGameCallback.cpp" />
 		<Unit filename="IGameCallback.h" />
 		<Unit filename="IGameEventsReceiver.h" />
+		<Unit filename="IHandlerBase.cpp" />
 		<Unit filename="IHandlerBase.h" />
 		<Unit filename="Interprocess.h" />
 		<Unit filename="JsonDetail.cpp" />

+ 2 - 0
lib/VCMI_lib.vcxproj

@@ -199,6 +199,7 @@
     <ClCompile Include="filesystem\Filesystem.cpp" />
     <ClCompile Include="filesystem\ResourceID.cpp" />
     <ClCompile Include="GameConstants.cpp" />
+    <ClCompile Include="IHandlerBase.cpp" />
     <ClCompile Include="JsonDetail.cpp" />
     <ClCompile Include="LogicalExpression.cpp" />
     <ClCompile Include="mapObjects\CArmedInstance.cpp" />
@@ -274,6 +275,7 @@
     <ClInclude Include="CCreatureSet.h" />
     <ClInclude Include="CGameInterface.h" />
     <ClInclude Include="CGameState.h" />
+    <ClInclude Include="CGameStateFwd.h" />
     <ClInclude Include="CGeneralTextHandler.h" />
     <ClInclude Include="CHeroHandler.h" />
     <ClInclude Include="CModHandler.h" />

+ 4 - 0
lib/VCMI_lib.vcxproj.filters

@@ -204,6 +204,7 @@
       <Filter>mapObjects</Filter>
     </ClCompile>
     <ClCompile Include="registerTypes\TypesMapObjects3.cpp" />
+    <ClCompile Include="IHandlerBase.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="CCreatureSet.h">
@@ -488,5 +489,8 @@
     <ClInclude Include="mapObjects\ObjectTemplate.h">
       <Filter>mapObjects</Filter>
     </ClInclude>
+    <ClInclude Include="CGameStateFwd.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>

+ 3 - 0
lib/mapObjects/CArmedInstance.h

@@ -13,6 +13,9 @@
  *
  */
 
+class BattleInfo;
+class CGameState;
+
 class DLL_LINKAGE CArmedInstance: public CGObjectInstance, public CBonusSystemNode, public CCreatureSet
 {
 public:

+ 6 - 3
lib/mapObjects/CBank.cpp

@@ -16,6 +16,8 @@
 #include "../CSoundBase.h"
 #include "CommonConstructors.h"
 #include "../CSpellHandler.h"
+#include "../IGameCallback.h"
+#include "../CGameState.h"
 
 using namespace boost::assign;
 
@@ -41,11 +43,12 @@ void CBank::initObj()
 	VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, cb->gameState()->getRandomGenerator());
 }
 
-const std::string & CBank::getHoverText() const
+std::string CBank::getHoverText(PlayerColor player) const
 {
+	// TODO: USE BANK_SPECIFIC NAMES
+	// TODO: record visited players
 	bool visited = (bc == nullptr);
-	hoverName = visitedTxt(visited); // FIXME: USE BANK_SPECIFIC NAMES
-	return hoverName;
+	return visitedTxt(visited);
 }
 
 void CBank::setConfig(const BankConfig & config)

+ 1 - 1
lib/mapObjects/CBank.h

@@ -32,7 +32,7 @@ public:
 	void setConfig(const BankConfig & bc);
 
 	void initObj() override;
-	const std::string & getHoverText() const override;
+	std::string getHoverText(PlayerColor player) const override;
 	void newTurn() const override;
 	bool wasVisited (PlayerColor player) const override;
 	void onHeroVisit(const CGHeroInstance * h) const override;

+ 9 - 8
lib/mapObjects/CGHeroInstance.cpp

@@ -14,10 +14,13 @@
 #include "../NetPacks.h"
 #include "../CGeneralTextHandler.h"
 #include "../CHeroHandler.h"
+#include "../CModHandler.h"
 #include "../CSoundBase.h"
 #include "../CSpellHandler.h"
 #include "CObjectClassesHandler.h"
-
+#include "../IGameCallback.h"
+#include "../CGameState.h"
+#include "../CCreatureHandler.h"
 
 using namespace boost::assign;
 
@@ -418,19 +421,17 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
 	}
 }
 
-const std::string & CGHeroInstance::getHoverText() const
+std::string CGHeroInstance::getObjectName() const
 {
 	if(ID != Obj::PRISON)
 	{
-		hoverName = VLC->generaltexth->allTexts[15];
+		std::string hoverName = VLC->generaltexth->allTexts[15];
 		boost::algorithm::replace_first(hoverName,"%s",name);
 		boost::algorithm::replace_first(hoverName,"%s", type->heroClass->name);
 		return hoverName;
 	}
 	else
-		hoverName = VLC->objtypeh->getObjectName(ID);
-
-	return hoverName;
+		return CGObjectInstance::getObjectName();
 }
 
 const std::string & CGHeroInstance::getBiography() const
@@ -999,11 +1000,11 @@ void CGHeroInstance::showNecromancyDialog(const CStackBasicDescriptor &raisedSta
 
 	cb->showInfoDialog(&iw);
 }
-
+/*
 int3 CGHeroInstance::getSightCenter() const
 {
 	return getPosition(false);
-}
+}*/
 
 int CGHeroInstance::getSightRadious() const
 {

+ 4 - 2
lib/mapObjects/CGHeroInstance.h

@@ -18,6 +18,8 @@
 
 class CHero;
 class CGBoat;
+class CGTownInstance;
+class TerrainTile;
 
 class CGHeroPlaceholder : public CGObjectInstance
 {
@@ -113,7 +115,7 @@ public:
 		}
 	} skillsInfo;
 
-	int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
+	//int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
 	int getSightRadious() const; //sight distance (should be used if player-owned structure)
 	//////////////////////////////////////////////////////////////////////////
 
@@ -205,7 +207,7 @@ public:
 
 	void initObj() override;
 	void onHeroVisit(const CGHeroInstance * h) const override;
-	const std::string & getHoverText() const override;
+	std::string getObjectName() const override;
 protected:
 	void setPropertyDer(ui8 what, ui32 val) override;//synchr
 

+ 3 - 0
lib/mapObjects/CGMarket.cpp

@@ -14,6 +14,9 @@
 
 #include "../NetPacks.h"
 #include "../CGeneralTextHandler.h"
+#include "../IGameCallback.h"
+#include "../CCreatureHandler.h"
+#include "../CGameState.h"
 
 using namespace boost::assign;
 

+ 2 - 0
lib/mapObjects/CGPandoraBox.cpp

@@ -15,6 +15,8 @@
 #include "../CSoundBase.h"
 
 #include "../CSpellHandler.h"
+#include "../StartInfo.h"
+#include "../IGameCallback.h"
 
 using namespace boost::assign;
 

+ 3 - 0
lib/mapObjects/CGPandoraBox.h

@@ -2,6 +2,7 @@
 
 #include "CObjectHandler.h"
 #include "CArmedInstance.h"
+#include "../ResourceSet.h"
 
 /*
  * CGPandoraBox.h, part of VCMI engine
@@ -13,6 +14,8 @@
  *
  */
 
+class InfoWindow;
+
 class DLL_LINKAGE CGPandoraBox : public CArmedInstance
 {
 public:

+ 19 - 15
lib/mapObjects/CGTownInstance.cpp

@@ -14,6 +14,9 @@
 
 #include "../NetPacks.h"
 #include "../CGeneralTextHandler.h"
+#include "../CModHandler.h"
+#include "../IGameCallback.h"
+#include "../CGameState.h"
 
 using namespace boost::assign;
 
@@ -55,7 +58,7 @@ void CGDwelling::initObj()
 	}
 }
 
-void CGDwelling::setProperty(ui8 what, ui32 val)
+void CGDwelling::setPropertyDer(ui8 what, ui32 val)
 {
 	switch (what)
 	{
@@ -77,8 +80,8 @@ void CGDwelling::setProperty(ui8 what, ui32 val)
 			creatures[0].second[0] = CreatureID(val);
 			break;
 	}
-	CGObjectInstance::setProperty(what,val);
 }
+
 void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const
 {
 	if(ID == Obj::REFUGEE_CAMP && !creatures[0].first) //Refugee Camp, no available cres
@@ -523,11 +526,15 @@ void CGTownInstance::onHeroLeave(const CGHeroInstance * h) const
 	cb->stopHeroVisitCastle(this, h);
 }
 
+std::string CGTownInstance::getObjectName() const
+{
+	return name + ", " + town->faction->name;
+}
+
 void CGTownInstance::initObj()
 ///initialize town structures
 {
 	blockVisit = true;
-	hoverName = name + ", " + town->faction->name;
 
 	if (subID == ETownType::DUNGEON)
 		creatures.resize(GameConstants::CREATURES_PER_TOWN+1);//extra dwelling for Dungeon
@@ -644,25 +651,22 @@ void CGTownInstance::newTurn() const
 			}
 	}
 }
-
+/*
 int3 CGTownInstance::getSightCenter() const
 {
 	return pos - int3(2,0,0);
 }
-
-ui8 CGTownInstance::getPassableness() const
+*/
+bool CGTownInstance::passableFor(PlayerColor color) const
 {
 	if (!armedGarrison())//empty castle - anyone can visit
-		return GameConstants::ALL_PLAYERS;
+		return true;
 	if ( tempOwner == PlayerColor::NEUTRAL )//neutral guarded - no one can visit
-		return 0;
-
-	ui8 mask = 0;
-	TeamState * ts = cb->gameState()->getPlayerTeam(tempOwner);
-	for(PlayerColor it : ts->players)
-		mask |= 1<<it.getNum();//allies - add to possible visitors
+		return false;
 
-	return mask;
+	if (cb->getPlayerRelations(tempOwner, color) != PlayerRelations::ENEMIES)
+		return true;
+	return false;
 }
 
 void CGTownInstance::getOutOffsets( std::vector<int3> &offsets ) const
@@ -1010,7 +1014,7 @@ void CGTownInstance::battleFinished(const CGHeroInstance *hero, const BattleResu
 		FoWChange fw;
 		fw.player = hero->tempOwner;
 		fw.mode = 1;
-		getSightTiles (fw.tiles); //update visibility for castle structures
+		cb->getTilesInRange(fw.tiles, getSightCenter(), getSightRadious(), tempOwner, 1);
 		cb->sendAndApply (&fw);
 	}
 }

+ 5 - 3
lib/mapObjects/CGTownInstance.h

@@ -17,6 +17,7 @@
  */
 
 class CCastleEvent;
+class CGTownInstance;
 
 class DLL_LINKAGE CSpecObjInfo
 {
@@ -59,7 +60,7 @@ public:
 	void initObj() override;
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void newTurn() const override;
-	void setProperty(ui8 what, ui32 val) override;
+	void setPropertyDer(ui8 what, ui32 val) override;
 	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
 	void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
 
@@ -200,8 +201,8 @@ public:
 
 	//////////////////////////////////////////////////////////////////////////
 
-	ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used
-	int3 getSightCenter() const override; //"center" tile from which the sight distance is calculated
+	bool passableFor(PlayerColor color) const;
+	//int3 getSightCenter() const override; //"center" tile from which the sight distance is calculated
 	int getSightRadious() const override; //returns sight distance
 	int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
 	void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
@@ -243,6 +244,7 @@ public:
 	void onHeroLeave(const CGHeroInstance * h) const override;
 	void initObj() override;
 	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
+	std::string getObjectName() const override;
 protected:
 	void setPropertyDer(ui8 what, ui32 val) override;
 };

+ 4 - 2
lib/mapObjects/CObjectClassesHandler.cpp

@@ -276,8 +276,10 @@ void CObjectClassesHandler::afterLoadFinalization()
 
 std::string CObjectClassesHandler::getObjectName(si32 type) const
 {
-	assert(objects.count(type));
-	return objects.at(type)->name;
+	if (objects.count(type))
+		return objects.at(type)->name;
+	logGlobal->errorStream() << "Access to non existing object of type "  << type;
+	return "";
 }
 
 void AObjectTypeHandler::setType(si32 type, si32 subtype)

+ 2 - 1
lib/mapObjects/CObjectClassesHandler.h

@@ -5,6 +5,7 @@
 #include "../GameConstants.h"
 #include "../ConstTransitivePtr.h"
 #include "../IHandlerBase.h"
+#include "../JsonNode.h"
 
 /*
  * CObjectClassesHandler.h, part of VCMI engine
@@ -64,7 +65,7 @@ public:
 			walkersStrength(0)
 		{}
 
-		bool operator <(const CArmyStructure & other)
+		bool operator <(const CArmyStructure & other) const
 		{
 			return this->totalStrength < other.totalStrength;
 		}

+ 24 - 87
lib/mapObjects/CObjectHandler.cpp

@@ -15,6 +15,9 @@
 #include "../CGeneralTextHandler.h"
 #include "../CHeroHandler.h"
 #include "../CSoundBase.h"
+#include "../filesystem/ResourceID.h"
+#include "../IGameCallback.h"
+#include "../CGameState.h"
 
 #include "CObjectClassesHandler.h"
 
@@ -53,12 +56,6 @@ static void showInfoDialog(const CGHeroInstance* h, const ui32 txtID, const ui16
 	showInfoDialog(playerID,txtID,soundID);
 }
 
-static std::string & visitedTxt(const bool visited)
-{
-	int id = visited ? 352 : 353;
-	return VLC->generaltexth->allTexts[id];
-}
-
 ///IObjectInterface
 void IObjectInterface::onHeroVisit(const CGHeroInstance * h) const
 {}
@@ -137,21 +134,11 @@ CGObjectInstance::CGObjectInstance():
 }
 CGObjectInstance::~CGObjectInstance()
 {
-	//if (state)
-	//	delete state;
-	//state=nullptr;
 }
 
-const std::string & CGObjectInstance::getHoverText() const
-{
-	return hoverName;
-}
 void CGObjectInstance::setOwner(PlayerColor ow)
 {
-	//if (state)
-	//	state->owner = ow;
-	//else
-		tempOwner = ow;
+	tempOwner = ow;
 }
 int CGObjectInstance::getWidth() const//returns width of object graphic in tiles
 {
@@ -203,29 +190,6 @@ std::set<int3> CGObjectInstance::getBlockedOffsets() const
 	return ret;
 }
 
-
-bool CGObjectInstance::operator<(const CGObjectInstance & cmp) const  //screen printing priority comparing
-{
-	if (appearance.printPriority != cmp.appearance.printPriority)
-		return appearance.printPriority > cmp.appearance.printPriority;
-
-	if(pos.y != cmp.pos.y)
-		return pos.y < cmp.pos.y;
-
-	if(cmp.ID==Obj::HERO && ID!=Obj::HERO)
-		return true;
-	if(cmp.ID!=Obj::HERO && ID==Obj::HERO)
-		return false;
-
-	if(!isVisitable() && cmp.isVisitable())
-		return true;
-	if(!cmp.isVisitable() && isVisitable())
-		return false;
-	if(this->pos.x<cmp.pos.x)
-		return true;
-	return false;
-}
-
 void CGObjectInstance::setType(si32 ID, si32 subID)
 {
 	const TerrainTile &tile = cb->gameState()->map->getTile(visitablePos());
@@ -252,6 +216,8 @@ void CGObjectInstance::initObj()
 
 void CGObjectInstance::setProperty( ui8 what, ui32 val )
 {
+	setPropertyDer(what, val); // call this before any actual changes (needed at least for dwellings)
+
 	switch(what)
 	{
 	case ObjProperty::OWNER:
@@ -267,7 +233,6 @@ void CGObjectInstance::setProperty( ui8 what, ui32 val )
 		subID = val;
 		break;
 	}
-	setPropertyDer(what, val);
 }
 
 void CGObjectInstance::setPropertyDer( ui8 what, ui32 val )
@@ -275,41 +240,14 @@ void CGObjectInstance::setPropertyDer( ui8 what, ui32 val )
 
 int3 CGObjectInstance::getSightCenter() const
 {
-	//return vistiable tile if possible
-	for(int i=0; i < 8; i++)
-		for(int j=0; j < 6; j++)
-			if(visitableAt(i,j))
-				return(pos + int3(i-7, j-5, 0));
-	return pos;
+	return visitablePos();
 }
 
 int CGObjectInstance::getSightRadious() const
 {
 	return 3;
 }
-void CGObjectInstance::getSightTiles(std::unordered_set<int3, ShashInt3> &tiles) const //returns reference to the set
-{
-	cb->getTilesInRange(tiles, getSightCenter(), getSightRadious(), tempOwner, 1);
-}
-void CGObjectInstance::hideTiles(PlayerColor ourplayer, int radius) const
-{
-	for (auto i = cb->gameState()->teams.begin(); i != cb->gameState()->teams.end(); i++)
-	{
-		if ( !vstd::contains(i->second.players, ourplayer ))//another team
-		{
-			for (auto & elem : i->second.players)
-				if ( cb->getPlayer(elem)->status == EPlayerStatus::INGAME )//seek for living player (if any)
-				{
-					FoWChange fw;
-					fw.mode = 0;
-					fw.player = elem;
-					cb->getTilesInRange (fw.tiles, pos, radius, (elem), -1);
-					cb->sendAndApply (&fw);
-					break;
-				}
-		}
-	}
-}
+
 int3 CGObjectInstance::getVisitableOffset() const
 {
 	for(int y = 0; y < appearance.getHeight(); y++)
@@ -321,17 +259,6 @@ int3 CGObjectInstance::getVisitableOffset() const
 	return int3(0,0,0);
 }
 
-void CGObjectInstance::getNameVis( std::string &hname ) const
-{
-	const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
-	hname = VLC->objtypeh->getObjectName(ID);
-	if(h)
-	{
-		const bool visited = h->hasBonusFrom(Bonus::OBJECT,ID);
-		hname + " " + visitedTxt(visited);
-	}
-}
-
 void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) const
 {
 	GiveBonus gbonus;
@@ -343,6 +270,21 @@ void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) con
 	cb->giveHeroBonus(&gbonus);
 }
 
+std::string CGObjectInstance::getObjectName() const
+{
+	return VLC->objtypeh->getObjectName(ID);
+}
+
+std::string CGObjectInstance::getHoverText(PlayerColor player) const
+{
+	return getObjectName();
+}
+
+std::string CGObjectInstance::getHoverText(const CGHeroInstance * hero) const
+{
+	return getHoverText(hero->tempOwner);
+}
+
 void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const
 {
 	switch(ID)
@@ -366,11 +308,6 @@ void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const
 	}
 }
 
-ui8 CGObjectInstance::getPassableness() const
-{
-	return 0;
-}
-
 int3 CGObjectInstance::visitablePos() const
 {
 	return pos - getVisitableOffset();
@@ -383,7 +320,7 @@ bool CGObjectInstance::isVisitable() const
 
 bool CGObjectInstance::passableFor(PlayerColor color) const
 {
-	return getPassableness() & 1<<color.getNum();
+	return false;
 }
 
 CGObjectInstanceBySubIdFinder::CGObjectInstanceBySubIdFinder(CGObjectInstance * obj) : obj(obj)

+ 53 - 28
lib/mapObjects/CObjectHandler.h

@@ -2,7 +2,7 @@
 
 #include "ObjectTemplate.h"
 
-#include "../IGameCallback.h"
+//#include "../IGameCallback.h"
 #include "../int3.h"
 #include "../HeroBonus.h"
 
@@ -17,6 +17,9 @@
  */
 
 class CGHeroInstance;
+class IGameCallback;
+class CGObjectInstance;
+class MetaString;
 struct BattleResult;
 
 class DLL_LINKAGE IObjectInterface
@@ -95,60 +98,82 @@ public:
 class DLL_LINKAGE CGObjectInstance : public IObjectInterface
 {
 public:
-	mutable std::string hoverName;
-	int3 pos; //h3m pos
+	/// Position of bottom-right corner of object on map
+	int3 pos;
+	/// Type of object, e.g. town, hero, creature.
 	Obj ID;
-	si32 subID; //normal subID (this one from OH3 maps ;])
-	ObjectInstanceID id;//number of object in map's vector
+	/// Subtype of object, depends on type
+	si32 subID;
+	/// Index of object in map's list of objects
+	ObjectInstanceID id;
+	/// Defines appearance of object on map (animation, blocked tiles, blit order, etc)
 	ObjectTemplate appearance;
-
+	/// Current owner of an object (when below PLAYER_LIMIT)
 	PlayerColor tempOwner;
-	bool blockVisit; //if non-zero then blocks the tile but is visitable from neighbouring tile
+	/// If true hero can visit this object only from neighbouring tiles and can't stand on this object
+	bool blockVisit;
+
+	CGObjectInstance();
+	~CGObjectInstance();
+
+	/// "center" tile from which the sight distance is calculated
+	int3 getSightCenter() const;
 
-	virtual ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used
-	virtual int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
-	virtual int getSightRadious() const; //sight distance (should be used if player-owned structure)
-	bool passableFor(PlayerColor color) const;
-	void getSightTiles(std::unordered_set<int3, ShashInt3> &tiles) const; //returns reference to the set
 	PlayerColor getOwner() const;
 	void setOwner(PlayerColor ow);
+
+	/** APPEARANCE ACCESSORS **/
+
 	int getWidth() const; //returns width of object graphic in tiles
 	int getHeight() const; //returns height of object graphic in tiles
-	virtual bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos)
-	virtual int3 getVisitableOffset() const; //returns (x,y,0) offset to first visitable tile from bottom right obj tile (0,0,0) (h3m pos)
+	bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos)
 	int3 visitablePos() const;
 	bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos)
 	bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos)
 	std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object
 	std::set<int3> getBlockedOffsets() const; //returns set of relative positions blocked by this object
 	bool isVisitable() const; //returns true if object is visitable
-	bool operator<(const CGObjectInstance & cmp) const;  //screen printing priority comparing
-	void hideTiles(PlayerColor ourplayer, int radius) const;
-	CGObjectInstance();
-	virtual ~CGObjectInstance();
-	//CGObjectInstance(const CGObjectInstance & right);
-	//CGObjectInstance& operator=(const CGObjectInstance & right);
-	virtual const std::string & getHoverText() const;
 
+	/** VIRTUAL METHODS **/
+
+	/// Returns true if player can pass through visitable tiles of this object
+	virtual bool passableFor(PlayerColor color) const;
+	/// Range of revealed map around this object, counting from getSightCenter()
+	virtual int getSightRadious() const;
+	/// returns (x,y,0) offset to a visitable tile of object
+	virtual int3 getVisitableOffset() const;
+	/// Called mostly during map randomization to turn random object into a regular one (e.g. "Random Monster" into "Pikeman")
 	virtual void setType(si32 ID, si32 subID);
 
-	///IObjectInterface
+	/// returns text visible in status bar with specific hero/player active.
+
+	/// Returns generic name of object, without any player-specific info
+	virtual std::string getObjectName() const;
+
+	/// Returns hover name for situation when there are no selected heroes. Default = object name
+	virtual std::string getHoverText(PlayerColor player) const;
+	/// Returns hero-specific hover name, including visited/not visited info. Default = player-specific name
+	virtual std::string getHoverText(const CGHeroInstance * hero) const;
+
+	/** OVERRIDES OF IObjectInterface **/
+
 	void initObj() override;
 	void onHeroVisit(const CGHeroInstance * h) const override;
-	void setProperty(ui8 what, ui32 val) override;//synchr
-
-	friend class CGameHandler;
+	/// method for synchronous update. Note: For new properties classes should override setPropertyDer instead
+	void setProperty(ui8 what, ui32 val) override final;
 
+	//friend class CGameHandler;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & hoverName & pos & ID & subID & id & tempOwner & blockVisit & appearance;
+		h & pos & ID & subID & id & tempOwner & blockVisit & appearance;
 		//definfo is handled by map serializer
 	}
 protected:
-	virtual void setPropertyDer(ui8 what, ui32 val);//synchr
+	/// virtual method that allows synchronously update object state on server and all clients
+	virtual void setPropertyDer(ui8 what, ui32 val);
 
-	void getNameVis(std::string &hname) const;
+	/// Gives dummy bonus from this object to hero. Can be used to track visited state
 	void giveDummyBonus(ObjectInstanceID heroID, ui8 duration = Bonus::ONE_DAY) const;
 };
 

+ 14 - 30
lib/mapObjects/CQuest.cpp

@@ -17,6 +17,8 @@
 #include "../CGeneralTextHandler.h"
 #include "../CHeroHandler.h"
 #include "CObjectClassesHandler.h"
+#include "../IGameCallback.h"
+#include "../CGameState.h"
 
 using namespace boost::assign;
 
@@ -434,25 +436,15 @@ void CGSeerHut::getRolloverText (MetaString &text, bool onHover) const
 		text.addReplacement(seerName);
 }
 
-const std::string & CGSeerHut::getHoverText() const
+std::string CGSeerHut::getHoverText(PlayerColor player) const
 {
-	switch (ID)
+	std::string hoverName = getObjectName();
+	if (ID == Obj::SEER_HUT && quest->progress != CQuest::NOT_ACTIVE)
 	{
-	case Obj::SEER_HUT:
-		if (quest->progress != CQuest::NOT_ACTIVE)
-		{
-			hoverName = VLC->generaltexth->allTexts[347];
-			boost::algorithm::replace_first(hoverName,"%s", seerName);
-		}
-		else //just seer hut
-			hoverName = VLC->objtypeh->getObjectName(ID);
-		break;
-	case Obj::QUEST_GUARD:
-		hoverName = VLC->objtypeh->getObjectName(ID);
-		break;
-	default:
-		logGlobal->debugStream() << "unrecognized quest object";
+		hoverName = VLC->generaltexth->allTexts[347];
+		boost::algorithm::replace_first(hoverName,"%s", seerName);
 	}
+
 	if (quest->progress & quest->missionType) //rollover when the quest is active
 	{
 		MetaString ms;
@@ -757,19 +749,14 @@ bool CGKeys::wasMyColorVisited (PlayerColor player) const
 		return false;
 }
 
-const std::string& CGKeys::getHoverText() const
+std::string CGKeys::getHoverText(PlayerColor player) const
 {
-	bool visited = wasMyColorVisited (cb->getLocalPlayer());
-	hoverName = getName() + "\n" + visitedTxt(visited);
-	return hoverName;
+	return getObjectName() + "\n" + visitedTxt(wasMyColorVisited(player));
 }
 
-
-const std::string CGKeys::getName() const
+std::string CGKeys::getObjectName() const
 {
-	std::string name;
-	name = VLC->generaltexth->tentColors[subID] + " " + VLC->objtypeh->getObjectName(ID);
-	return name;
+	return VLC->generaltexth->tentColors[subID] + " " + CGObjectInstance::getObjectName();
 }
 
 bool CGKeymasterTent::wasVisited (PlayerColor player) const
@@ -853,10 +840,7 @@ void CGBorderGate::onHeroVisit( const CGHeroInstance * h ) const //TODO: passabi
 	}
 }
 
-ui8 CGBorderGate::getPassableness() const
+bool CGBorderGate::passableFor(PlayerColor color) const
 {
-	ui8 ret = 0;
-	for (int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++)
-		ret |= wasMyColorVisited(PlayerColor(i))<<i;
-	return ret;
+	return wasMyColorVisited(color);
 }

+ 6 - 4
lib/mapObjects/CQuest.h

@@ -16,6 +16,8 @@
  *
  */
 
+class CGCreature;
+
 class DLL_LINKAGE CQuest
 {
 public:
@@ -95,7 +97,7 @@ public:
 
 	CGSeerHut() : IQuestObject(){};
 	void initObj() override;
-	const std::string & getHoverText() const override;
+	std::string getHoverText(PlayerColor player) const override;
 	void newTurn() const override;
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
@@ -138,10 +140,10 @@ public:
 	static std::map <PlayerColor, std::set <ui8> > playerKeyMap; //[players][keysowned]
 	//SubID 0 - lightblue, 1 - green, 2 - red, 3 - darkblue, 4 - brown, 5 - purple, 6 - white, 7 - black
 
-	const std::string getName() const; //depending on color
 	bool wasMyColorVisited (PlayerColor player) const;
 
-	const std::string & getHoverText() const override;
+	std::string getObjectName() const override; //depending on color
+	std::string getHoverText(PlayerColor player) const override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
@@ -189,7 +191,7 @@ public:
 	CGBorderGate() : CGBorderGuard(){};
 	void onHeroVisit(const CGHeroInstance * h) const override;
 
-	ui8 getPassableness() const override;
+	bool passableFor(PlayerColor color) const override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 3 - 1
lib/mapObjects/CRewardableConstructor.cpp

@@ -5,6 +5,7 @@
 #include "../StringConstants.h"
 #include "../CCreatureHandler.h"
 #include "JsonRandom.h"
+#include "../IGameCallback.h"
 
 /*
  * CRewardableConstructor.cpp, part of VCMI engine
@@ -95,7 +96,8 @@ void CRandomRewardObjectInfo::configureObject(CRewardableObject * object, CRando
 		info.reward.movePoints = JsonRandom::loadValue(reward["movePoints"], rng);
 		info.reward.movePercentage = JsonRandom::loadValue(reward["movePercentage"], rng, -1);
 
-		info.reward.bonuses = JsonRandom::loadBonuses(reward["bonuses"]);
+		//FIXME: compile this line on Visual
+		//info.reward.bonuses = JsonRandom::loadBonuses(reward["bonuses"]);
 
 		info.reward.primary = JsonRandom::loadPrimary(reward["primary"], rng);
 		info.reward.secondary = JsonRandom::loadSecondary(reward["secondary"], rng);

+ 11 - 10
lib/mapObjects/CRewardableObject.cpp

@@ -15,6 +15,8 @@
 #include "../CGeneralTextHandler.h"
 #include "../CSoundBase.h"
 #include "../NetPacks.h"
+#include "../IGameCallback.h"
+#include "../CGameState.h"
 
 #include "CObjectClassesHandler.h"
 
@@ -375,19 +377,18 @@ static std::string & visitedTxt(const bool visited)
 	return VLC->generaltexth->allTexts[id];
 }
 
-const std::string & CRewardableObject::getHoverText() const
+std::string CRewardableObject::getHoverText(PlayerColor player) const
 {
-	const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
-	hoverName = VLC->objtypeh->getObjectName(ID);
 	if(visitMode != VISIT_UNLIMITED)
-	{
-		bool visited = wasVisited(cb->getCurrentPlayer());
-		if (h)
-			visited |= wasVisited(h);
+		return getObjectName() + " " + visitedTxt(wasVisited(player));
+	return getObjectName();
+}
 
-		hoverName += " " + visitedTxt(visited);
-	}
-	return hoverName;
+std::string CRewardableObject::getHoverText(const CGHeroInstance * hero) const
+{
+	if(visitMode != VISIT_UNLIMITED)
+		return getObjectName() + " " + visitedTxt(wasVisited(hero));
+	return getObjectName();
 }
 
 void CRewardableObject::setPropertyDer(ui8 what, ui32 val)

+ 3 - 1
lib/mapObjects/CRewardableObject.h

@@ -4,6 +4,7 @@
 #include "CArmedInstance.h"
 
 #include "../NetPacksBase.h"
+#include "../ResourceSet.h"
 
 /*
  * CRewardableObject.h, part of VCMI engine
@@ -209,7 +210,8 @@ protected:
 
 public:
 	void setPropertyDer(ui8 what, ui32 val) override;
-	const std::string & getHoverText() const override;
+	std::string getHoverText(PlayerColor player) const override;
+	std::string getHoverText(const CGHeroInstance * hero) const override;
 
 	/// Visitability checks. Note that hero check includes check for hero owner (returns true if object was visited by player)
 	bool wasVisited (PlayerColor player) const override;

+ 2 - 0
lib/mapObjects/CommonConstructors.cpp

@@ -8,6 +8,8 @@
 #include "../CHeroHandler.h"
 #include "../CCreatureHandler.h"
 #include "JsonRandom.h"
+#include "../CModHandler.h"
+#include "../IGameCallback.h"
 
 /*
  * CommonConstructors.cpp, part of VCMI engine

+ 6 - 4
lib/mapObjects/JsonRandom.cpp

@@ -206,10 +206,12 @@ namespace JsonRandom
 		return ret;
 	}
 
-	std::vector<Component> loadComponents(const JsonNode & value)
-	{
-		//TODO
-	}
+	//std::vector<Component> loadComponents(const JsonNode & value)
+	//{
+	//	std::vector<Component> ret;
+	//	return ret;
+	//	//TODO
+	//}
 
 	std::vector<Bonus> DLL_LINKAGE loadBonuses(const JsonNode & value)
 	{

+ 14 - 14
lib/mapObjects/JsonRandom.h

@@ -23,28 +23,28 @@ class CStackBasicDescriptor;
 
 namespace JsonRandom
 {
-	struct RandomStackInfo
+	struct DLL_LINKAGE RandomStackInfo
 	{
 		std::vector<const CCreature *> allowedCreatures;
 		si32 minAmount;
 		si32 maxAmount;
 	};
 
-	si32 loadValue(const JsonNode & value, CRandomGenerator & rng, si32 defaultValue = 0);
-	TResources loadResources(const JsonNode & value, CRandomGenerator & rng);
-	std::vector<si32> loadPrimary(const JsonNode & value, CRandomGenerator & rng);
-	std::map<SecondarySkill, si32> loadSecondary(const JsonNode & value, CRandomGenerator & rng);
+	DLL_LINKAGE si32 loadValue(const JsonNode & value, CRandomGenerator & rng, si32 defaultValue = 0);
+	DLL_LINKAGE TResources loadResources(const JsonNode & value, CRandomGenerator & rng);
+	DLL_LINKAGE std::vector<si32> loadPrimary(const JsonNode & value, CRandomGenerator & rng);
+	DLL_LINKAGE std::map<SecondarySkill, si32> loadSecondary(const JsonNode & value, CRandomGenerator & rng);
 
-	ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng);
-	std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng);
+	DLL_LINKAGE ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng);
+	DLL_LINKAGE std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng);
 
-	SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells);
-	std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells);
+	DLL_LINKAGE SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells);
+	DLL_LINKAGE std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells);
 
-	CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng);
-	std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng);
-	std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value);
+	DLL_LINKAGE CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng);
+	DLL_LINKAGE std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng);
+	DLL_LINKAGE std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value);
 
-	std::vector<Bonus> DLL_LINKAGE loadBonuses(const JsonNode & value);
-	std::vector<Component> loadComponents(const JsonNode & value);
+	DLL_LINKAGE std::vector<Bonus> loadBonuses(const JsonNode & value);
+	//DLL_LINKAGE std::vector<Component> loadComponents(const JsonNode & value);
 }

+ 111 - 93
lib/mapObjects/MiscObjects.cpp

@@ -14,9 +14,12 @@
 #include "../NetPacks.h"
 #include "../CGeneralTextHandler.h"
 #include "../CSoundBase.h"
+#include "../CModHandler.h"
 
 #include "CObjectClassesHandler.h"
 #include "../CSpellHandler.h"
+#include "../IGameCallback.h"
+#include "../CGameState.h"
 
 using namespace boost::assign;
 
@@ -78,17 +81,16 @@ bool CPlayersVisited::wasVisited( TeamID team ) const
 	return false;
 }
 
-const std::string & CGCreature::getHoverText() const
+std::string CGCreature::getHoverText(PlayerColor player) const
 {
 	if(stacks.empty())
 	{
-		static const std::string errorValue("!!!INVALID_STACK!!!");
-
 		//should not happen...
 		logGlobal->errorStream() << "Invalid stack at tile " << pos << ": subID=" << subID << "; id=" << id;
-		return errorValue; // references to temporary are illegal - use pre-constructed string
+		return "!!!INVALID_STACK!!!";
 	}
 
+	std::string hoverName;
 	MetaString ms;
 	int pom = stacks.begin()->second->getQuantityID();
 	pom = 172 + 3*pom;
@@ -96,30 +98,34 @@ const std::string & CGCreature::getHoverText() const
 	ms << " " ;
 	ms.addTxt(MetaString::CRE_PL_NAMES,subID);
 	ms.toString(hoverName);
+	return hoverName;
+}
 
-	if(const CGHeroInstance *selHero = cb->getSelectedHero(cb->getCurrentPlayer()))
-	{
-		const JsonNode & texts = VLC->generaltexth->localizedTexts["adventureMap"]["monsterThreat"];
-
-		hoverName += texts["title"].String();
-		int choice;
-		double ratio = ((double)getArmyStrength() / selHero->getTotalStrength());
-		     if (ratio < 0.1)  choice = 0;
-		else if (ratio < 0.25) choice = 1;
-		else if (ratio < 0.6)  choice = 2;
-		else if (ratio < 0.9)  choice = 3;
-		else if (ratio < 1.1)  choice = 4;
-		else if (ratio < 1.3)  choice = 5;
-		else if (ratio < 1.8)  choice = 6;
-		else if (ratio < 2.5)  choice = 7;
-		else if (ratio < 4)    choice = 8;
-		else if (ratio < 8)    choice = 9;
-		else if (ratio < 20)   choice = 10;
-		else                   choice = 11;
-		hoverName += texts["levels"].Vector()[choice].String();
-	}
+std::string CGCreature::getHoverText(const CGHeroInstance * hero) const
+{
+	std::string hoverName = getHoverText(hero->tempOwner);
+
+	const JsonNode & texts = VLC->generaltexth->localizedTexts["adventureMap"]["monsterThreat"];
+
+	hoverName += texts["title"].String();
+	int choice;
+	double ratio = ((double)getArmyStrength() / hero->getTotalStrength());
+		 if (ratio < 0.1)  choice = 0;
+	else if (ratio < 0.25) choice = 1;
+	else if (ratio < 0.6)  choice = 2;
+	else if (ratio < 0.9)  choice = 3;
+	else if (ratio < 1.1)  choice = 4;
+	else if (ratio < 1.3)  choice = 5;
+	else if (ratio < 1.8)  choice = 6;
+	else if (ratio < 2.5)  choice = 7;
+	else if (ratio < 4)    choice = 8;
+	else if (ratio < 8)    choice = 9;
+	else if (ratio < 20)   choice = 10;
+	else                   choice = 11;
+	hoverName += texts["levels"].Vector()[choice].String();
 	return hoverName;
 }
+
 void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
 {
 	int action = takenAction(h);
@@ -443,21 +449,6 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &
 	}
 	else
 	{
-		//int killedAmount=0;
-		//for(std::set<std::pair<ui32,si32> >::iterator i=result->casualties[1].begin(); i!=result->casualties[1].end(); i++)
-		//	if(i->first == subID)
-		//		killedAmount += i->second;
-		//cb->setAmount(id, slots.find(0)->second.second - killedAmount);
-
-		/*
-		MetaString ms;
-		int pom = slots.find(0)->second.getQuantityID();
-		pom = 174 + 3*pom + 1;
-		ms << std::pair<ui8,ui32>(6,pom) << " " << std::pair<ui8,ui32>(7,subID);
-		cb->setHoverName(id,&ms);
-		cb->setObjProperty(id, 11, slots.begin()->second.count * 1000);
-		*/
-
 		//merge stacks into one
 		TSlots::const_iterator i;
 		CCreature * cre = VLC->creh->creatures[formation.basicType];
@@ -554,37 +545,47 @@ void CGMine::initObj()
 		assert(!possibleResources.empty());
 		producedResource = *RandomGeneratorUtil::nextItem(possibleResources, cb->gameState()->getRandomGenerator());
 		tempOwner = PlayerColor::NEUTRAL;
-		hoverName = VLC->generaltexth->mines[7].first + "\n" + VLC->generaltexth->allTexts[202] + " " + troglodytes->getQuantityTXT(false) + " " + troglodytes->type->namePl;
 	}
 	else
 	{
 		producedResource = static_cast<Res::ERes>(subID);
-
-		MetaString ms;
-		ms << std::pair<ui8,ui32>(9,producedResource);
 		if(tempOwner >= PlayerColor::PLAYER_LIMIT)
 			tempOwner = PlayerColor::NEUTRAL;
-		else
-			ms << " (" << std::pair<ui8,ui32>(6,23+tempOwner.getNum()) << ")";
-		ms.toString(hoverName);
 	}
 
 	producedQuantity = defaultResProduction();
 }
 
-void CGMine::flagMine(PlayerColor player) const
+std::string CGMine::getObjectName() const
 {
-	assert(tempOwner != player);
-	cb->setOwner(this, player); //not ours? flag it!
+	return VLC->generaltexth->mines.at(subID).first;
+}
 
-	MetaString ms;
-	ms << std::pair<ui8,ui32>(9,subID) << "\n(" << std::pair<ui8,ui32>(6,23+player.getNum()) << ")";
-	if(subID == 7)
+std::string CGMine::getHoverText(PlayerColor player) const
+{
+
+	std::string hoverName = getObjectName(); // Sawmill
+
+	if (tempOwner != PlayerColor::NEUTRAL)
+	{
+		hoverName += "\n";
+		hoverName += VLC->generaltexth->arraytxt[23 + tempOwner.getNum()]; // owned by Red Player
+		hoverName += "\n(" + VLC->generaltexth->restypes[producedResource] + ")";
+	}
+
+	for (auto & slot : Slots()) // guarded by a few Pikeman
 	{
-		ms << "(%s)";
-		ms.addReplacement(MetaString::RES_NAMES, producedResource);
+		hoverName += "\n";
+		hoverName += getRoughAmount(slot.first);
+		hoverName += getCreature(slot.first)->namePl;
 	}
-	cb->setHoverName(this,&ms);
+	return hoverName;
+}
+
+void CGMine::flagMine(PlayerColor player) const
+{
+	assert(tempOwner != player);
+	cb->setOwner(this, player); //not ours? flag it!
 
 	InfoWindow iw;
 	iw.soundID = soundBase::FLAGMINE;
@@ -626,10 +627,14 @@ void CGMine::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) con
 		cb->startBattleI(hero, this);
 }
 
+std::string CGResource::getHoverText(PlayerColor player) const
+{
+	return VLC->generaltexth->restypes[subID];
+}
+
 void CGResource::initObj()
 {
 	blockVisit = true;
-	hoverName = VLC->generaltexth->restypes[subID];
 
 	if(!amount)
 	{
@@ -866,7 +871,6 @@ void CGArtifact::initObj()
 	blockVisit = true;
 	if(ID == Obj::ARTIFACT)
 	{
-		hoverName = VLC->arth->artifacts[subID]->Name();
 		if(!storedArtifact->artType)
 			storedArtifact->setType(VLC->arth->artifacts[subID]);
 	}
@@ -879,6 +883,11 @@ void CGArtifact::initObj()
 	//assert(storedArtifact->artType->id == subID); //this does not stop desync
 }
 
+std::string CGArtifact::getObjectName() const
+{
+	return VLC->arth->artifacts[subID]->Name();
+}
+
 void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
 {
 	if(!stacksCount())
@@ -985,20 +994,25 @@ void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const
 	cb->showInfoDialog(&iw);
 }
 
-const std::string & CGWitchHut::getHoverText() const
+std::string CGWitchHut::getHoverText(PlayerColor player) const
 {
-	hoverName = VLC->objtypeh->getObjectName(ID);
-	if(wasVisited(cb->getLocalPlayer()))
+	std::string hoverName = getObjectName();
+	if(wasVisited(player))
 	{
 		hoverName += "\n" + VLC->generaltexth->allTexts[356]; // + (learn %s)
 		boost::algorithm::replace_first(hoverName,"%s",VLC->generaltexth->skillName[ability]);
-		const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
-		if(h && h->getSecSkillLevel(SecondarySkill(ability))) //hero knows that ability
-			hoverName += "\n\n" + VLC->generaltexth->allTexts[357]; // (Already learned)
 	}
 	return hoverName;
 }
 
+std::string CGWitchHut::getHoverText(const CGHeroInstance * hero) const
+{
+	std::string hoverName = getHoverText(hero->tempOwner);
+	if(hero->getSecSkillLevel(SecondarySkill(ability))) //hero knows that ability
+		hoverName += "\n\n" + VLC->generaltexth->allTexts[357]; // (Already learned)
+	return hoverName;
+}
+
 void CGMagicWell::onHeroVisit( const CGHeroInstance * h ) const
 {
 	int message;
@@ -1020,10 +1034,9 @@ void CGMagicWell::onHeroVisit( const CGHeroInstance * h ) const
 	showInfoDialog(h,message,soundBase::faerie);
 }
 
-const std::string & CGMagicWell::getHoverText() const
+std::string CGMagicWell::getHoverText(const CGHeroInstance * hero) const
 {
-	getNameVis(hoverName);
-	return hoverName;
+	return getObjectName() + " " + visitedTxt(hero->hasBonusFrom(Bonus::OBJECT,ID));
 }
 
 void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const
@@ -1048,7 +1061,12 @@ void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const
 	case Obj::COVER_OF_DARKNESS:
 	{
 		iw.text.addTxt (MetaString::ADVOB_TXT, 31);
-		hideTiles(h->tempOwner, 20);
+		for (auto player : cb->gameState()->players)
+		{
+			if (cb->getPlayerStatus(player.first) == EPlayerStatus::INGAME &&
+				cb->getPlayerRelations(player.first, h->tempOwner) == PlayerRelations::ENEMIES)
+				cb->changeFogOfWar(visitablePos(), 20, player.first, true);
+		}
 		break;
 	}
 	}
@@ -1115,20 +1133,25 @@ void CGShrine::initObj()
 	}
 }
 
-const std::string & CGShrine::getHoverText() const
+std::string CGShrine::getHoverText(PlayerColor player) const
 {
-	hoverName = VLC->objtypeh->getObjectName(ID);
-	if(wasVisited(cb->getCurrentPlayer())) //TODO: use local player, not current
+	std::string hoverName = getObjectName();
+	if(wasVisited(player))
 	{
 		hoverName += "\n" + VLC->generaltexth->allTexts[355]; // + (learn %s)
 		boost::algorithm::replace_first(hoverName,"%s", spell.toSpell()->name);
-		const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
-		if(h && vstd::contains(h->spells,spell)) //hero knows that ability
-			hoverName += "\n\n" + VLC->generaltexth->allTexts[354]; // (Already learned)
 	}
 	return hoverName;
 }
 
+std::string CGShrine::getHoverText(const CGHeroInstance * hero) const
+{
+	std::string hoverName = getHoverText(hero->tempOwner);
+	if(vstd::contains(hero->spells, spell)) //hero knows that spell
+		hoverName += "\n\n" + VLC->generaltexth->allTexts[354]; // (Already learned)
+	return hoverName;
+}
+
 void CGSignBottle::initObj()
 {
 	//if no text is set than we pick random from the predefined ones
@@ -1250,19 +1273,18 @@ void CGGarrison::onHeroVisit (const CGHeroInstance *h) const
 	cb->showGarrisonDialog(id, h->id, removableUnits);
 }
 
-ui8 CGGarrison::getPassableness() const
+bool CGGarrison::passableFor(PlayerColor player) const
 {
+	//FIXME: identical to same method in CGTownInstance
+
 	if ( !stacksCount() )//empty - anyone can visit
-		return GameConstants::ALL_PLAYERS;
+		return true;
 	if ( tempOwner == PlayerColor::NEUTRAL )//neutral guarded - no one can visit
-		return 0;
-
-	ui8 mask = 0;
-	TeamState * ts = cb->gameState()->getPlayerTeam(tempOwner);
-	for(PlayerColor it : ts->players)
-		mask |= 1<<it.getNum(); //allies - add to possible visitors
+		return false;
 
-	return mask;
+	if (cb->getPlayerRelations(tempOwner, player) != PlayerRelations::ENEMIES)
+		return true;
+	return false;
 }
 
 void CGGarrison::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
@@ -1325,10 +1347,9 @@ void CGSirens::initObj()
 	blockVisit = true;
 }
 
-const std::string & CGSirens::getHoverText() const
+std::string CGSirens::getHoverText(const CGHeroInstance * hero) const
 {
-	getNameVis(hoverName);
-	return hoverName;
+	return getObjectName() + " " + visitedTxt(hero->hasBonusFrom(Bonus::OBJECT,ID));
 }
 
 void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
@@ -1499,11 +1520,9 @@ void CGObelisk::initObj()
 	obeliskCount++;
 }
 
-const std::string & CGObelisk::getHoverText() const
+std::string CGObelisk::getHoverText(PlayerColor player) const
 {
-	bool visited = wasVisited(cb->getLocalPlayer());
-	hoverName = VLC->objtypeh->getObjectName(ID) + " " + visitedTxt(visited);
-	return hoverName;
+	return getObjectName() + " " + visitedTxt(wasVisited(player));
 }
 
 void CGObelisk::setPropertyDer( ui8 what, ui32 val )
@@ -1553,11 +1572,10 @@ void CGLighthouse::initObj()
 	}
 }
 
-const std::string & CGLighthouse::getHoverText() const
+std::string CGLighthouse::getHoverText(PlayerColor player) const
 {
-	hoverName = VLC->objtypeh->getObjectName(ID);
 	//TODO: owned by %s player
-	return hoverName;
+	return getObjectName();
 }
 
 void CGLighthouse::giveBonusTo( PlayerColor player ) const

+ 19 - 8
lib/mapObjects/MiscObjects.h

@@ -2,6 +2,7 @@
 
 #include "CObjectHandler.h"
 #include "CArmedInstance.h"
+#include "../ResourceSet.h"
 
 /*
  * MiscObjects.h, part of VCMI engine
@@ -48,7 +49,8 @@ public:
 	bool refusedJoining;
 
 	void onHeroVisit(const CGHeroInstance * h) const override;
-	const std::string & getHoverText() const override;
+	std::string getHoverText(PlayerColor player) const override;
+	std::string getHoverText(const CGHeroInstance * hero) const override;
 	void initObj() override;
 	void newTurn() const override;
 	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
@@ -106,7 +108,8 @@ public:
 	std::vector<si32> allowedAbilities;
 	ui32 ability;
 
-	const std::string & getHoverText() const override;
+	std::string getHoverText(PlayerColor player) const override;
+	std::string getHoverText(const CGHeroInstance * hero) const override;
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void initObj() override;
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -138,7 +141,7 @@ class DLL_LINKAGE CGGarrison : public CArmedInstance
 public:
 	bool removableUnits;
 
-	ui8 getPassableness() const;
+	bool passableFor(PlayerColor color) const override;
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
 
@@ -159,6 +162,8 @@ public:
 	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
 	void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
 
+	std::string getObjectName() const override;
+
 	void pick( const CGHeroInstance * h ) const;
 	void initObj() override;
 
@@ -179,6 +184,7 @@ public:
 	void initObj() override;
 	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
 	void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
+	std::string getHoverText(PlayerColor player) const override;
 
 	void collectRes(PlayerColor player) const;
 
@@ -195,7 +201,8 @@ public:
 	SpellID spell; //id of spell or NONE if random
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void initObj() override;
-	const std::string & getHoverText() const override;
+	std::string getHoverText(PlayerColor player) const override;
+	std::string getHoverText(const CGHeroInstance * hero) const override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
@@ -217,6 +224,10 @@ public:
 	void flagMine(PlayerColor player) const;
 	void newTurn() const override;
 	void initObj() override;
+
+	std::string getObjectName() const override;
+	std::string getHoverText(PlayerColor player) const override;
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & static_cast<CArmedInstance&>(*this);
@@ -245,7 +256,7 @@ class DLL_LINKAGE CGMagicWell : public CGObjectInstance //objects giving bonuses
 {
 public:
 	void onHeroVisit(const CGHeroInstance * h) const override;
-	const std::string & getHoverText() const override;
+	std::string getHoverText(const CGHeroInstance * hero) const override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
@@ -257,7 +268,7 @@ class DLL_LINKAGE CGSirens : public CGObjectInstance
 {
 public:
 	void onHeroVisit(const CGHeroInstance * h) const override;
-	const std::string & getHoverText() const override;
+	std::string getHoverText(const CGHeroInstance * hero) const override;
 	void initObj() override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -352,7 +363,7 @@ public:
 
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void initObj() override;
-	const std::string & getHoverText() const override;
+	std::string getHoverText(PlayerColor player) const override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
@@ -367,7 +378,7 @@ class DLL_LINKAGE CGLighthouse : public CGObjectInstance
 public:
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void initObj() override;
-	const std::string & getHoverText() const override;
+	std::string getHoverText(PlayerColor player) const override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 1 - 1
lib/mapping/CMap.cpp

@@ -432,7 +432,7 @@ const CGObjectInstance * CMap::getObjectiveObjectFrom(int3 pos, Obj::EObj type)
 	}
 	assert(bestMatch != nullptr); // if this happens - victory conditions or map itself is very, very broken
 
-	logGlobal->errorStream() << "Will use " << bestMatch->getHoverText() << " from " << bestMatch->pos;
+	logGlobal->errorStream() << "Will use " << bestMatch->getObjectName() << " from " << bestMatch->pos;
 	return bestMatch;
 }
 

+ 10 - 161
lib/mapping/MapFormatH3M.cpp

@@ -1063,56 +1063,6 @@ void CMapLoaderH3M::readObjects()
 				nobj = readHero(idToBeGiven);
 				break;
 			}
-		case Obj::ARENA:
-		case Obj::MERCENARY_CAMP:
-		case Obj::MARLETTO_TOWER:
-		case Obj::STAR_AXIS:
-		case Obj::GARDEN_OF_REVELATION:
-		case Obj::LEARNING_STONE:
-		case Obj::TREE_OF_KNOWLEDGE:
-		case Obj::LIBRARY_OF_ENLIGHTENMENT:
-		case Obj::SCHOOL_OF_MAGIC:
-		case Obj::SCHOOL_OF_WAR:
-			{
-				nobj = new CGVisitableOPH();
-				break;
-			}
-		case Obj::MYSTICAL_GARDEN:
-		case Obj::WINDMILL:
-		case Obj::WATER_WHEEL:
-			{
-				nobj = new CGVisitableOPW();
-				break;
-			}
-		case Obj::MONOLITH_ONE_WAY_ENTRANCE:
-		case Obj::MONOLITH_ONE_WAY_EXIT:
-		case Obj::MONOLITH_TWO_WAY:
-		case Obj::SUBTERRANEAN_GATE:
-		case Obj::WHIRLPOOL:
-			{
-				nobj = new CGTeleport();
-				break;
-			}
-		case Obj::CAMPFIRE:
-		case Obj::FLOTSAM:
-		case Obj::SEA_CHEST:
-		case Obj::SHIPWRECK_SURVIVOR:
-			{
-				nobj = new CGPickable();
-				break;
-			}
-		case Obj::TREASURE_CHEST:
-				if(objTempl.subid == 0)
-				{
-					nobj = new CGPickable();
-				}
-				else
-				{
-					//WoG pickable object
-					//TODO: possible special handling
-					nobj = new CGObjectInstance();
-				}
-				break;
 		case Obj::MONSTER:  //Monster
 		case Obj::RANDOM_MONSTER:
 		case Obj::RANDOM_MONSTER_L1:
@@ -1330,12 +1280,6 @@ void CMapLoaderH3M::readObjects()
 				reader.skip(3);
 				break;
 			}
-		case Obj::REFUGEE_CAMP:
-		case Obj::WAR_MACHINE_FACTORY:
-			{
-				nobj = new CGDwelling();
-				break;
-			}
 		case Obj::SHRINE_OF_MAGIC_INCANTATION:
 		case Obj::SHRINE_OF_MAGIC_GESTURE:
 		case Obj::SHRINE_OF_MAGIC_THOUGHT:
@@ -1458,52 +1402,6 @@ void CMapLoaderH3M::readObjects()
 				nobj = guard;
 				break;
 			}
-		case Obj::FAERIE_RING:
-		case Obj::SWAN_POND:
-		case Obj::IDOL_OF_FORTUNE:
-		case Obj::FOUNTAIN_OF_FORTUNE:
-		case Obj::RALLY_FLAG:
-		case Obj::OASIS:
-		case Obj::TEMPLE:
-		case Obj::WATERING_HOLE:
-		case Obj::FOUNTAIN_OF_YOUTH:
-		case Obj::BUOY:
-		case Obj::MERMAID:
-		case Obj::STABLES:
-			{
-				nobj = new CGBonusingObject();
-				break;
-			}
-		case Obj::MAGIC_WELL:
-			{
-				nobj = new CGMagicWell();
-				break;
-			}
-		case Obj::COVER_OF_DARKNESS:
-		case Obj::REDWOOD_OBSERVATORY:
-		case Obj::PILLAR_OF_FIRE:
-			{
-				nobj = new CGObservatory();
-				break;
-			}
-		case Obj::CORPSE:
-		case Obj::LEAN_TO:
-		case Obj::WAGON:
-		case Obj::WARRIORS_TOMB:
-			{
-				nobj = new CGOnceVisitable();
-				break;
-			}
-		case Obj::BOAT:
-			{
-				nobj = new CGBoat();
-				break;
-			}
-		case Obj::SIRENS:
-			{
-				nobj = new CGSirens();
-				break;
-			}
 		case Obj::SHIPYARD:
 			{
 				nobj = new CGShipyard();
@@ -1531,11 +1429,6 @@ void CMapLoaderH3M::readObjects()
 					hp->power = 0;
 				}
 
-				break;
-			}
-		case Obj::KEYMASTER:
-			{
-				nobj = new CGKeymasterTent();
 				break;
 			}
 		case Obj::BORDERGUARD:
@@ -1550,21 +1443,6 @@ void CMapLoaderH3M::readObjects()
 				map->addQuest (nobj);
 				break;
 			}
-		case Obj::EYE_OF_MAGI:
-		case Obj::HUT_OF_MAGI:
-			{
-				nobj = new CGMagi();
-				break;
-			}
-		case Obj::CREATURE_BANK:
-		case Obj::DERELICT_SHIP:
-		case Obj::DRAGON_UTOPIA:
-		case Obj::CRYPT:
-		case Obj::SHIPWRECK:
-			{
-				nobj = new CBank();
-				break;
-			}
 		case Obj::PYRAMID: //Pyramid of WoG object
 			{
 				if(objTempl.subid == 0)
@@ -1579,53 +1457,24 @@ void CMapLoaderH3M::readObjects()
 				}
 				break;
 			}
-		case Obj::CARTOGRAPHER:
-			{
-				nobj = new CCartographer();
-				break;
-			}
-		case Obj::MAGIC_SPRING:
-			{
-				nobj = new CGMagicSpring();
-				break;
-			}
-		case Obj::DEN_OF_THIEVES:
-			{
-				nobj = new CGDenOfthieves();
-				break;
-			}
-		case Obj::OBELISK:
-			{
-				nobj = new CGObelisk();
-				break;
-			}
 		case Obj::LIGHTHOUSE: //Lighthouse
 			{
 				nobj = new CGLighthouse();
 				nobj->tempOwner = PlayerColor(reader.readUInt32());
 				break;
 			}
-		case Obj::ALTAR_OF_SACRIFICE:
-		case Obj::TRADING_POST:
-		case Obj::FREELANCERS_GUILD:
-		case Obj::TRADING_POST_SNOW:
-			{
-				nobj = new CGMarket();
-				break;
-			}
-		case Obj::UNIVERSITY:
-			{
-				nobj = new CGUniversity();
-				break;
-			}
-		case Obj::BLACK_MARKET:
-			{
-				nobj = new CGBlackMarket();
-				break;
-			}
 		default: //any other object
 			{
-				nobj = new CGObjectInstance();
+				if (VLC->objtypeh->knownSubObjects(objTempl.id).count(objTempl.subid))
+				{
+					nobj = VLC->objtypeh->getHandlerFor(objTempl.id, objTempl.subid)->create(objTempl);
+				}
+				else
+				{
+					logGlobal->warnStream() << "Unrecognized object: " << objTempl.id << ":" << objTempl.subid << " at " << objPos
+											<< " on map " << map->name;
+					nobj = new CGObjectInstance();
+				}
 				break;
 			}
 		}

+ 1 - 1
lib/registerTypes/RegisterTypes.h

@@ -12,6 +12,7 @@
 #include "../mapObjects/CRewardableConstructor.h"
 #include "../mapObjects/CommonConstructors.h"
 #include "../mapObjects/MapObjects.h"
+#include "../CObstacleInstance.h"
 
 /*
  * RegisterTypes.h, part of VCMI engine
@@ -234,7 +235,6 @@ void registerTypesClientPacks1(Serializer &s)
 	s.template registerType<CPackForClient, NewTurn>();
 	s.template registerType<CPackForClient, InfoWindow>();
 	s.template registerType<CPackForClient, SetObjectProperty>();
-	s.template registerType<CPackForClient, SetHoverName>();
 	s.template registerType<CPackForClient, ShowInInfobox>();
 	s.template registerType<CPackForClient, AdvmapSpellCast>();
 	s.template registerType<CPackForClient, OpenWindow>();

+ 2 - 2
scripting/erm/ERMInterpreter.cpp

@@ -2,8 +2,8 @@
 #include "ERMInterpreter.h"
 
 #include <cctype>
-#include "../../lib/mapObjects/CObjectHandler.h"
-#include "../../lib/mapObjects/MapObjects.h"
+#include "../../lib/mapObjects/CObjectHandler.h"
+#include "../../lib/mapObjects/MapObjects.h"
 #include "../../lib/CHeroHandler.h"
 #include "../../lib/CCreatureHandler.h"
 #include "../../lib/VCMIDirs.h"

+ 25 - 11
server/CGameHandler.cpp

@@ -1351,9 +1351,13 @@ void CGameHandler::newTurn()
 		}
 		if (t->hasBonusOfType (Bonus::DARKNESS))
 		{
-			t->hideTiles(t->getOwner(), t->getBonusLocalFirst(Selector::type(Bonus::DARKNESS))->val);
+			for (auto player : gameState()->players)
+			{
+				if (getPlayerStatus(player.first) == EPlayerStatus::INGAME &&
+					getPlayerRelations(player.first, t->tempOwner) == PlayerRelations::ENEMIES)
+					changeFogOfWar(t->visitablePos(), t->getBonusLocalFirst(Selector::type(Bonus::DARKNESS))->val, player.first, true);
+			}
 		}
-		//unhiding what shouldn't be hidden? //that's handled in netpacks client
 	}
 
 	if(newMonth)
@@ -1845,12 +1849,6 @@ void CGameHandler::setOwner(const CGObjectInstance * obj, PlayerColor owner)
 	}
 }
 
-void CGameHandler::setHoverName(const CGObjectInstance * obj, MetaString* name)
-{
-	SetHoverName shn(obj->id, *name);
-	sendAndApply(&shn);
-}
-
 void CGameHandler::showBlockingDialog( BlockingDialog *iw )
 {
 	auto dialogQuery = make_shared<CBlockingDialogQuery>(*iw);
@@ -2523,7 +2521,7 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID requestedID,
 	FoWChange fw;
 	fw.player = t->tempOwner;
 	fw.mode = 1;
-	t->getSightTiles(fw.tiles);
+	getTilesInRange(fw.tiles, t->getSightCenter(), t->getSightRadious(), t->tempOwner, 1);
 	sendAndApply(&fw);
 
 	if(t->visitingHero)
@@ -4988,7 +4986,7 @@ bool CGameHandler::isAllowedExchange( ObjectInstanceID id1, ObjectInstanceID id2
 
 void CGameHandler::objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h )
 {
-	logGlobal->traceStream()  << h->nodeName() << " visits " << obj->getHoverText();
+	logGlobal->debugStream()  << h->nodeName() << " visits " << obj->getObjectName() << "(" << obj->ID << ":" << obj->subID << ")";
 	auto visitQuery = make_shared<CObjectVisitQuery>(obj, h, obj->visitablePos());
 	queries.addQuery(visitQuery); //TODO real visit pos
 
@@ -5227,7 +5225,7 @@ void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player)
 	}
 }
 
-void CGameHandler::getVictoryLossMessage(PlayerColor player, EVictoryLossCheckResult victoryLossCheckResult, InfoWindow & out) const
+void CGameHandler::getVictoryLossMessage(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult, InfoWindow & out) const
 {
 	out.player = player;
 	out.text.clear();
@@ -6252,6 +6250,22 @@ void CGameHandler::removeAfterVisit(const CGObjectInstance *object)
 	assert("This function needs to be called during the object visit!");
 }
 
+void CGameHandler::changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide)
+{
+	std::unordered_set<int3, ShashInt3> tiles;
+	getTilesInRange(tiles, center, radius, player, hide? -1 : 1);
+	changeFogOfWar(tiles, player, hide);
+}
+
+void CGameHandler::changeFogOfWar(std::unordered_set<int3, ShashInt3> &tiles, PlayerColor player, bool hide)
+{
+	FoWChange fow;
+	fow.tiles = tiles;
+	fow.player = player;
+	fow.mode = hide? 0 : 1;
+	sendAndApply(&fow);
+}
+
 bool CGameHandler::isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero)
 {
 	if(auto topQuery = queries.topQuery(hero->getOwner()))

+ 3 - 2
server/CGameHandler.h

@@ -127,7 +127,6 @@ public:
 	bool removeObject(const CGObjectInstance * obj) override;
 	void setBlockVis(ObjectInstanceID objid, bool bv) override;
 	void setOwner(const CGObjectInstance * obj, PlayerColor owner) override;
-	void setHoverName(const CGObjectInstance * objid, MetaString * name) override;
 	void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false) override;
 	void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) override; 
 	//void showInfoDialog(InfoWindow *iw) override;
@@ -174,6 +173,8 @@ public:
 	void changeObjPos(ObjectInstanceID objid, int3 newPos, ui8 flags) override;
 	void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override;
 
+	void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override;
+	void changeFogOfWar(std::unordered_set<int3, ShashInt3> &tiles, PlayerColor player, bool hide) override;
 
 	bool isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero) override;
 
@@ -289,7 +290,7 @@ public:
 private:
 	std::list<PlayerColor> generatePlayerTurnOrder() const;
 	void makeStackDoNothing(const CStack * next);
-	void getVictoryLossMessage(PlayerColor player, EVictoryLossCheckResult victoryLossCheckResult, InfoWindow & out) const;
+	void getVictoryLossMessage(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult, InfoWindow & out) const;
 
 	// Check for victory and loss conditions
 	void checkVictoryLossConditionsForPlayer(PlayerColor player);

+ 2 - 2
server/CQuery.cpp

@@ -322,7 +322,7 @@ CHeroLevelUpDialogQuery::CHeroLevelUpDialogQuery(const HeroLevelUp &Hlu)
 void CHeroLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color)
 {
 	assert(answer);
-	logGlobal->traceStream() << "Completing hero level-up query. " << hlu.hero->getHoverText() << " gains skill " << *answer;
+	logGlobal->traceStream() << "Completing hero level-up query. " << hlu.hero->getObjectName() << " gains skill " << *answer;
 	gh->levelUpHero(hlu.hero, hlu.skills[*answer]);
 }
 
@@ -340,7 +340,7 @@ CCommanderLevelUpDialogQuery::CCommanderLevelUpDialogQuery(const CommanderLevelU
 void CCommanderLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color)
 {
 	assert(answer);
-	logGlobal->traceStream() << "Completing commander level-up query. Commander of hero " << clu.hero->getHoverText() << " gains skill " << *answer;
+	logGlobal->traceStream() << "Completing commander level-up query. Commander of hero " << clu.hero->getObjectName() << " gains skill " << *answer;
 	gh->levelUpCommander(clu.hero->commander, clu.skills[*answer]);
 }