Browse Source

Added per-team tracking of scouted state of an object

Ivan Savenko 1 year ago
parent
commit
cb5df096c1

+ 5 - 0
lib/CPlayerState.h

@@ -153,6 +153,8 @@ public:
 	//TODO: boost::array, bool if possible
 	boost::multi_array<ui8, 3> fogOfWarMap; //[z][x][y] true - visible, false - hidden
 
+	std::set<ObjectInstanceID> scoutedObjects;
+
 	TeamState();
 
 	template <typename Handler> void serialize(Handler &h)
@@ -173,6 +175,9 @@ public:
 
 		h & fogOfWarMap;
 		h & static_cast<CBonusSystemNode&>(*this);
+
+		if (h.version >= Handler::Version::TEAM_STATE_SCOUTED_OBJECTS)
+			h & scoutedObjects;
 	}
 
 };

+ 1 - 1
lib/mapObjects/CBank.cpp

@@ -137,7 +137,7 @@ bool CBank::wasVisited (PlayerColor player) const
 
 void CBank::onHeroVisit(const CGHeroInstance * h) const
 {
-	ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_TEAM, id, h->id);
+	ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_PLAYER, id, h->id);
 	cb->sendAndApply(&cov);
 
 	if(!bankConfig && (ID.toEnum() == Obj::CREATURE_BANK || ID.toEnum() == Obj::DRAGON_UTOPIA))

+ 18 - 33
lib/mapObjects/CRewardableObject.cpp

@@ -108,24 +108,30 @@ bool CRewardableObject::guardedPresently() const
 	return stacksCount() > 0;
 }
 
-void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const
+void CRewardableObject::onHeroVisit(const CGHeroInstance *hero) const
 {
+	if(!wasScouted(hero->getOwner()))
+	{
+		ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_SCOUTED, id, hero->id);
+		cb->sendAndApply(&cov);
+	}
+
 	if (guardedPresently())
 	{
-		auto guardedIndexes = getAvailableRewards(h, Rewardable::EEventType::EVENT_GUARDED);
+		auto guardedIndexes = getAvailableRewards(hero, Rewardable::EEventType::EVENT_GUARDED);
 		auto guardedReward = configuration.info.at(guardedIndexes.at(0));
 
 		// ask player to confirm attack
 		BlockingDialog bd(true, false);
-		bd.player = h->getOwner();
+		bd.player = hero->getOwner();
 		bd.text = guardedReward.message;
-		bd.components = getPopupComponents(h->getOwner());
+		bd.components = getPopupComponents(hero->getOwner());
 
 		cb->showBlockingDialog(&bd);
 	}
 	else
 	{
-		doHeroVisit(h);
+		doHeroVisit(hero);
 	}
 }
 
@@ -192,7 +198,7 @@ void CRewardableObject::doHeroVisit(const CGHeroInstance *h) const
 
 		if(!objectRemovalPossible && getAvailableRewards(h, Rewardable::EEventType::EVENT_FIRST_VISIT).empty())
 		{
-			ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_TEAM, id, h->id);
+			ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_PLAYER, id, h->id);
 			cb->sendAndApply(&cov);
 		}
 	}
@@ -202,7 +208,7 @@ void CRewardableObject::doHeroVisit(const CGHeroInstance *h) const
 
 		if (!wasVisited(h->getOwner()))
 		{
-			ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_TEAM, id, h->id);
+			ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_PLAYER, id, h->id);
 			cb->sendAndApply(&cov);
 		}
 
@@ -236,27 +242,6 @@ void CRewardableObject::blockingDialogAnswered(const CGHeroInstance * hero, int3
 	}
 	else
 	{
-		if(answer == 0)
-		{
-			switch(configuration.visitMode)
-			{
-				case Rewardable::VISIT_UNLIMITED:
-				case Rewardable::VISIT_BONUS:
-				case Rewardable::VISIT_HERO:
-				case Rewardable::VISIT_LIMITER:
-				{
-					// workaround for object with refusable reward not getting marked as visited
-					// TODO: better solution that would also work for player-visitable objects
-					if(!wasScouted(hero->getOwner()))
-					{
-						ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_TEAM, id, hero->id);
-						cb->sendAndApply(&cov);
-					}
-				}
-			}
-			return; // player refused
-		}
-
 		if(answer > 0 && answer - 1 < configuration.info.size())
 		{
 			auto list = getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT);
@@ -274,7 +259,7 @@ void CRewardableObject::markAsVisited(const CGHeroInstance * hero) const
 {
 	cb->setObjPropertyValue(id, ObjProperty::REWARD_CLEARED, true);
 
-	ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD, id, hero->id);
+	ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_HERO, id, hero->id);
 	cb->sendAndApply(&cov);
 }
 
@@ -330,7 +315,7 @@ bool CRewardableObject::wasVisited(PlayerColor player) const
 
 bool CRewardableObject::wasScouted(PlayerColor player) const
 {
-	return vstd::contains(cb->getPlayerState(player)->visitedObjects, ObjectInstanceID(id));
+	return vstd::contains(cb->getPlayerTeam(player)->scoutedObjects, ObjectInstanceID(id));
 }
 
 bool CRewardableObject::wasVisited(const CGHeroInstance * h) const
@@ -418,9 +403,6 @@ std::vector<Component> CRewardableObject::getPopupComponentsImpl(PlayerColor pla
 	if (!wasScouted(player))
 		return {};
 
-	if (!configuration.showScoutedPreview)
-		return {};
-
 	if (guardedPresently())
 	{
 		if (!VLC->settings()->getBoolean(EGameSettings::BANKS_SHOW_GUARDS_COMPOSITION))
@@ -442,6 +424,9 @@ std::vector<Component> CRewardableObject::getPopupComponentsImpl(PlayerColor pla
 	}
 	else
 	{
+		if (!configuration.showScoutedPreview)
+			return {};
+
 		auto rewardIndices = getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT);
 		if (rewardIndices.empty() && !configuration.info.empty())
 		{

+ 16 - 19
lib/networkPacks/NetPacksLib.cpp

@@ -1035,32 +1035,32 @@ void ChangeObjPos::applyGs(CGameState *gs)
 void ChangeObjectVisitors::applyGs(CGameState *gs)
 {
 	switch (mode) {
-		case VISITOR_ADD:
+		case VISITOR_ADD_HERO:
+			gs->getPlayerTeam(gs->getHero(hero)->tempOwner)->scoutedObjects.insert(object);
 			gs->getHero(hero)->visitedObjects.insert(object);
 			gs->getPlayerState(gs->getHero(hero)->tempOwner)->visitedObjects.insert(object);
 			break;
-		case VISITOR_ADD_TEAM:
-			{
-				TeamState *ts = gs->getPlayerTeam(gs->getHero(hero)->tempOwner);
-				for(const auto & color : ts->players)
-				{
-					gs->getPlayerState(color)->visitedObjects.insert(object);
-				}
-			}
+		case VISITOR_ADD_PLAYER:
+			gs->getPlayerTeam(gs->getHero(hero)->tempOwner)->scoutedObjects.insert(object);
+			for(const auto & color : gs->getPlayerTeam(gs->getHero(hero)->tempOwner)->players)
+				gs->getPlayerState(color)->visitedObjects.insert(object);
+
 			break;
 		case VISITOR_CLEAR:
+			// remove visit info from all heroes, including those that are not present on map
 			for (CGHeroInstance * hero : gs->map->allHeroes)
-			{
 				if (hero)
-				{
-					hero->visitedObjects.erase(object); // remove visit info from all heroes, including those that are not present on map
-				}
-			}
+					hero->visitedObjects.erase(object);
 
 			for(auto &elem : gs->players)
-			{
 				elem.second.visitedObjects.erase(object);
-			}
+
+			for(auto &elem : gs->teams)
+				elem.second.scoutedObjects.erase(object);
+
+			break;
+		case VISITOR_SCOUTED:
+			gs->getPlayerTeam(gs->getHero(hero)->tempOwner)->scoutedObjects.insert(object);
 
 			break;
 		case VISITOR_GLOBAL:
@@ -1069,9 +1069,6 @@ void ChangeObjectVisitors::applyGs(CGameState *gs)
 				gs->getPlayerState(gs->getHero(hero)->tempOwner)->visitedObjectsGlobal.insert({objectPtr->ID, objectPtr->subID});
 				break;
 			}
-		case VISITOR_REMOVE:
-			gs->getHero(hero)->visitedObjects.erase(object);
-			break;
 	}
 }
 

+ 5 - 5
lib/networkPacks/PacksForClient.h

@@ -1216,11 +1216,11 @@ struct DLL_LINKAGE ChangeObjectVisitors : public CPackForClient
 {
 	enum VisitMode
 	{
-		VISITOR_ADD,      // mark hero as one that have visited this object
-		VISITOR_ADD_TEAM, // mark team as one that have visited this object
-		VISITOR_GLOBAL,   // mark player as one that have visited object of this type
-		VISITOR_REMOVE,   // unmark visitor, reversed to ADD
-		VISITOR_CLEAR     // clear all visitors from this object (object reset)
+		VISITOR_ADD_HERO,   // mark hero as one that have visited this object
+		VISITOR_ADD_PLAYER, // mark player as one that have visited this object instance
+		VISITOR_GLOBAL,     // mark player as one that have visited object of this type
+		VISITOR_SCOUTED,    // marks targeted team as having scouted this object
+		VISITOR_CLEAR,      // clear all visitors from this object (object reset)
 	};
 	VisitMode mode = VISITOR_CLEAR; // uses VisitMode enum
 	ObjectInstanceID object;

+ 2 - 1
lib/serializer/ESerializationVersion.h

@@ -59,6 +59,7 @@ enum class ESerializationVersion : int32_t
 	CHRONICLES_SUPPORT, // 860 - support for heroes chronicles
 	PER_MAP_GAME_SETTINGS, // 861 - game settings are now stored per-map
 	CAMPAIGN_OUTRO_SUPPORT, // 862 - support for campaign outro video
+	REWARDABLE_BANKS, // 863 - team state contains list of scouted objects, coast visitable rewardable objects
 
-	CURRENT = CAMPAIGN_OUTRO_SUPPORT
+	CURRENT = REWARDABLE_BANKS
 };