Browse Source

Add proper visitation checks for netpacks

Ivan Savenko 2 năm trước cách đây
mục cha
commit
b807c3855b
3 tập tin đã thay đổi với 45 bổ sung0 xóa
  1. 39 0
      server/CGameHandler.cpp
  2. 3 0
      server/CGameHandler.h
  3. 3 0
      server/processors/HeroPoolProcessor.cpp

+ 39 - 0
server/CGameHandler.cpp

@@ -2418,6 +2418,7 @@ bool CGameHandler::recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dst
 	}
 	else
 	{
+		COMPLAIN_RET_FALSE_IF(isVisitActiveForHero(dwelling, hero), "Cannot recruit: can only recruit by visiting hero!");
 		COMPLAIN_RET_FALSE_IF(!hero || hero->getOwner() != player, "Cannot recruit: can only recruit to owned hero!");
 	}
 
@@ -4084,8 +4085,46 @@ void CGameHandler::changeFogOfWar(std::unordered_set<int3> &tiles, PlayerColor p
 	sendAndApply(&fow);
 }
 
+bool CGameHandler::isVisitActiveForAny(const CGObjectInstance *obj)
+{
+	for (auto const & query : queries->allQueries())
+	{
+		auto visit = std::dynamic_pointer_cast<const CObjectVisitQuery>(query);
+		if (visit && visit->visitedObject == obj)
+			return true;
+	}
+	return false;
+}
+
+bool CGameHandler::isVisitActiveForPlayer(const CGObjectInstance *obj, PlayerColor player)
+{
+	for (auto const & query : queries->allQueries())
+	{
+		auto visit = std::dynamic_pointer_cast<const CObjectVisitQuery>(query);
+		if (visit && visit->visitedObject == obj && visit->visitingHero->getOwner() == player)
+			return true;
+	}
+	return false;
+}
+
+bool CGameHandler::isVisitActiveForHero(const CGObjectInstance *obj, const CGHeroInstance *hero)
+{
+	for (auto const & query : queries->allQueries())
+	{
+		auto visit = std::dynamic_pointer_cast<const CObjectVisitQuery>(query);
+		if (visit && visit->visitedObject == obj && visit->visitingHero == hero)
+			return true;
+	}
+	return false;
+}
+
 bool CGameHandler::isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero)
 {
+	assert(isVisitActiveForHero(obj, hero));
+	// Check top query of targeted player:
+	// If top query is NOT visit to targeted object then we assume that
+	// visitation query is covered by other query that must be answered first
+
 	if (auto topQuery = queries->topQuery(hero->getOwner()))
 		if (auto visit = std::dynamic_pointer_cast<const CObjectVisitQuery>(topQuery))
 			return !(visit->visitedObject == obj && visit->visitingHero == hero);

+ 3 - 0
server/CGameHandler.h

@@ -153,6 +153,9 @@ public:
 	
 	void castSpell(const spells::Caster * caster, SpellID spellID, const int3 &pos) override;
 
+	bool isVisitActiveForAny(const CGObjectInstance *obj);
+	bool isVisitActiveForPlayer(const CGObjectInstance *obj, PlayerColor player);
+	bool isVisitActiveForHero(const CGObjectInstance *obj, const CGHeroInstance *hero);
 	bool isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero) override;
 	void setObjProperty(ObjectInstanceID objid, int prop, si64 val) override;
 	void showInfoDialog(InfoWindow * iw) override;

+ 3 - 0
server/processors/HeroPoolProcessor.cpp

@@ -174,6 +174,9 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
 
 	if(mapObject->ID == Obj::TAVERN)
 	{
+		if (!gameHandler->isVisitActiveForPlayer(mapObject, player) && gameHandler->complain("Can't buy hero in tavern you are not visiting!"))
+			return false;
+
 		if(gameHandler->getTile(mapObject->visitablePos())->visitableObjects.back() != mapObject && gameHandler->complain("Tavern entry must be unoccupied!"))
 			return false;
 	}