Sfoglia il codice sorgente

Nullkiller: various fixes for town portal and other

Andrii Danylchenko 4 anni fa
parent
commit
e95ccda5de

+ 23 - 0
AI/Nullkiller/AIUtility.cpp

@@ -258,6 +258,29 @@ bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater)
 	return false;
 }
 
+bool isObjectPassable(const CGObjectInstance * obj)
+{
+	return isObjectPassable(obj, ai->playerID, cb->getPlayerRelations(obj->tempOwner, ai->playerID));
+}
+
+// Pathfinder internal helper
+bool isObjectPassable(const CGObjectInstance * obj, PlayerColor playerColor, PlayerRelations::PlayerRelations objectRelations)
+{
+	if((obj->ID == Obj::GARRISON || obj->ID == Obj::GARRISON2)
+		&& objectRelations != PlayerRelations::ENEMIES)
+		return true;
+
+	if(obj->ID == Obj::BORDER_GATE)
+	{
+		auto quest = dynamic_cast<const CGKeys *>(obj);
+
+		if(quest->passableFor(playerColor))
+			return true;
+	}
+
+	return false;
+}
+
 bool isBlockedBorderGate(int3 tileToHit) //TODO: is that function needed? should be handled by pathfinder
 {
 	if(cb->getTile(tileToHit)->topVisitableId() != Obj::BORDER_GATE)

+ 3 - 1
AI/Nullkiller/AIUtility.h

@@ -167,7 +167,9 @@ void foreach_neighbour(const int3 & pos, std::function<void(const int3 & pos)> f
 void foreach_neighbour(CCallback * cbp, const int3 & pos, std::function<void(CCallback * cbp, const int3 & pos)> foo); // avoid costly retrieval of thread-specific pointer
 
 bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater);
-bool isBlockedBorderGate(int3 tileToHit);
+//bool isBlockedBorderGate(int3 tileToHit);
+bool isObjectPassable(const CGObjectInstance * obj);
+bool isObjectPassable(const CGObjectInstance * obj, PlayerColor playerColor, PlayerRelations::PlayerRelations objectRelations);
 bool isBlockVisitObj(const int3 & pos);
 
 bool isWeeklyRevisitable(const CGObjectInstance * obj);

+ 2 - 1
AI/Nullkiller/Analyzers/ObjectClusterizer.cpp

@@ -113,7 +113,8 @@ const CGObjectInstance * ObjectClusterizer::getBlocker(const AIPath & path) cons
 			|| blocker->ID == Obj::QUEST_GUARD
 			|| blocker->ID == Obj::BORDER_GATE)
 		{
-			return blocker;
+			if(!isObjectPassable(blocker))
+				return blocker;
 		}
 	}
 

+ 1 - 1
AI/Nullkiller/Behaviors/ClusterBehavior.cpp

@@ -82,7 +82,7 @@ Goals::TGoalVec ClusterBehavior::decomposeCluster(std::shared_ptr<ObjectCluster>
 		{
 			blockerPaths.back().nodes.insert(blockerPaths.back().nodes.begin(), *node);
 
-			if(node->coord == blockerPos)
+			if(node->coord == blockerPos || cb->getGuardingCreaturePosition(node->coord) == blockerPos)
 				break;
 		}
 

+ 20 - 2
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -19,6 +19,9 @@
 #include "../../../lib/PathfinderUtil.h"
 #include "../../../lib/CPlayerState.h"
 
+/// 1-3 - position on map, 4 - layer (air, water, land), 5 - chain (normal, battle, spellcast and combinations)
+boost::multi_array<AIPathNode, 5> nodes;
+
 AINodeStorage::AINodeStorage(const int3 & Sizes)
 	: sizes(Sizes)
 {
@@ -827,6 +830,14 @@ void AINodeStorage::calculateTownPortalTeleportations(std::vector<CGPathNode *>
 		actorsOfInitial.insert(aiNode->actor->baseActor);
 	}
 
+	std::map<const CGHeroInstance *, int> maskMap;
+
+	for(std::shared_ptr<ChainActor> basicActor : actors)
+	{
+		if(basicActor->hero)
+			maskMap[basicActor->hero] = basicActor->chainMask;
+	}
+
 	for(const ChainActor * actor : actorsOfInitial)
 	{
 		if(!actor->hero)
@@ -851,8 +862,15 @@ void AINodeStorage::calculateTownPortalTeleportations(std::vector<CGPathNode *>
 			for(const CGTownInstance * targetTown : towns)
 			{
 				// TODO: allow to hide visiting hero in garrison
-				if(targetTown->visitingHero && targetTown->visitingHero != actor->hero)
-					continue;
+				if(targetTown->visitingHero)
+				{
+					auto basicMask = maskMap[targetTown->visitingHero.get()];
+					bool heroIsInChain = (actor->chainMask & basicMask) != 0;
+					bool sameActorInTown = actor->chainMask == basicMask;
+
+					if(sameActorInTown || !heroIsInChain)
+						continue;
+				}
 
 				auto nodeOptional = townPortalFinder.createTownPortalNode(targetTown);
 

+ 0 - 2
AI/Nullkiller/Pathfinding/AINodeStorage.h

@@ -106,8 +106,6 @@ class AINodeStorage : public INodeStorage
 private:
 	int3 sizes;
 
-	/// 1-3 - position on map, 4 - layer (air, water, land), 5 - chain (normal, battle, spellcast and combinations)
-	boost::multi_array<AIPathNode, 5> nodes;
 	const CPlayerSpecificInfoCallback * cb;
 	const VCAI * ai;
 	std::unique_ptr<FuzzyHelper> dangerEvaluator;

+ 1 - 1
AI/Nullkiller/Pathfinding/Actions/BoatActions.h

@@ -37,7 +37,7 @@ namespace AIPathfinding
 			AIPathNode * dstMode,
 			const AIPathNode * srcNode) const override;
 
-		virtual bool canAct(const AIPathNode * source) const;
+		virtual bool canAct(const AIPathNode * source) const override;
 
 		virtual const ChainActor * getActor(const ChainActor * sourceActor) const override;
 

+ 4 - 12
AI/Nullkiller/Pathfinding/Rules/AIPreviousNodeRule.cpp

@@ -26,20 +26,12 @@ namespace AIPathfinding
 		if(source.node->action == CGPathNode::ENodeAction::BLOCKING_VISIT 
 			|| source.node->action == CGPathNode::ENodeAction::VISIT)
 		{
-			if(source.nodeObject)
+			if(source.nodeObject
+				&& isObjectPassable(source.nodeObject, pathfinderHelper->hero->tempOwner, source.objectRelations))
 			{
-				if((source.nodeObject->ID == Obj::GARRISON || source.nodeObject->ID == Obj::GARRISON2)
-					&& source.heroRelations != PlayerRelations::ENEMIES)
-					return;
-
-				if(source.nodeObject->ID == Obj::BORDER_GATE)
-				{
-					auto quest = dynamic_cast<const CGBorderGate *>(source.nodeObject);
-
-					if(quest->wasMyColorVisited(pathfinderHelper->hero->tempOwner))
-						return;
-				}
+				return;
 			}
+
 			// we can not directly bypass objects, we need to interact with them first
 			destination.node->theNodeBefore = source.node;
 

+ 5 - 6
AI/Nullkiller/VCAI.cpp

@@ -30,7 +30,7 @@ extern FuzzyHelper * fh;
 
 class CGVisitableOPW;
 
-const float SAFE_ATTACK_CONSTANT = 1.5;
+const float SAFE_ATTACK_CONSTANT = 1.2;
 
 //one thread may be turn of AI and another will be handling a side effect for AI2
 boost::thread_specific_ptr<CCallback> cb;
@@ -758,13 +758,12 @@ void VCAI::makeTurn()
 	boost::shared_lock<boost::shared_mutex> gsLock(CGameState::mutex);
 	setThreadName("VCAI::makeTurn");
 
-	switch(cb->getDate(Date::DAY_OF_WEEK))
-	{
-	case 1:
+	if(cb->getDate(Date::DAY_OF_WEEK) == 1)
 	{
 		townVisitsThisWeek.clear();
 		std::vector<const CGObjectInstance *> objs;
 		retrieveVisitableObjs(objs, true);
+
 		for(const CGObjectInstance * obj : objs)
 		{
 			if(isWeeklyRevisitable(obj))
@@ -773,15 +772,15 @@ void VCAI::makeTurn()
 				vstd::erase_if_present(alreadyVisited, obj);
 			}
 		}
-		break;
-	}
 	}
+
 	markHeroAbleToExplore(primaryHero());
 	visitedHeroes.clear();
 
 	if(cb->getDate(Date::DAY) == 1)
 	{
 		retrieveVisitableObjs();
+		cb->sendMessage("vcmieagles");
 	}
 
 	try