Browse Source

Nullkiller: capture guarded artifacts and other fixes

Andrii Danylchenko 4 years ago
parent
commit
5344df51c6

+ 5 - 4
AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp

@@ -123,9 +123,6 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
 				if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
 					continue;
 
-				if(ai->nullkiller->getHeroLockedReason(way->hero.get()) == HeroLockedReason::STARTUP)
-					continue;
-
 				way->evaluationContext.closestWayRatio
 					= closestWay->evaluationContext.movementCost / way->evaluationContext.movementCost;
 
@@ -149,7 +146,6 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
 bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const
 {
 	const CGObjectInstance* objInstance = obj;
-
 	if(!objInstance)
 		return false;
 
@@ -162,6 +158,11 @@ bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const
 	{
 		return false;
 	}
+	
+	if(isObjectRemovable(obj))
+	{
+		return true;
+	}
 
 	const int3 pos = objInstance->visitablePos();
 

+ 0 - 6
AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp

@@ -148,9 +148,6 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
 		if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
 			continue;
 
-		if(ai->nullkiller->getHeroLockedReason(way->hero.get()) == HeroLockedReason::STARTUP)
-			continue;
-
 		way->evaluationContext.closestWayRatio = 1;
 
 		tasks.push_back(sptr(*way));
@@ -246,9 +243,6 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
 		if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
 			continue;
 
-		if(ai->nullkiller->getHeroLockedReason(way->hero.get()) == HeroLockedReason::STARTUP)
-			continue;
-
 		way->evaluationContext.closestWayRatio = 1;
 
 		tasks.push_back(sptr(*way));

+ 31 - 3
AI/Nullkiller/Engine/Nullkiller.cpp

@@ -69,12 +69,13 @@ Goals::TSubgoal Nullkiller::choseBestTask(std::shared_ptr<Behavior> behavior) co
 void Nullkiller::resetAiState()
 {
 	lockedHeroes.clear();
-
 	dangerHitMap->reset();
 }
 
 void Nullkiller::updateAiState()
 {
+	activeHero = nullptr;
+
 	ai->validateVisitableObjs();
 	dangerHitMap->updateHitMap();
 
@@ -94,17 +95,44 @@ void Nullkiller::updateAiState()
 	buildAnalyzer->update();
 }
 
+bool Nullkiller::isHeroLocked(const CGHeroInstance * hero) const
+{
+	return getHeroLockedReason(hero) != HeroLockedReason::NOT_LOCKED;
+}
+
 bool Nullkiller::arePathHeroesLocked(const AIPath & path) const
 {
+	if(getHeroLockedReason(path.targetHero) == HeroLockedReason::STARTUP)
+	{
+#if AI_TRACE_LEVEL >= 1
+		logAi->trace("Hero %s is locked by STARTUP. Discarding %s", path.targetHero->name, path.toString());
+#endif
+		return true;
+	}
+
 	for(auto & node : path.nodes)
 	{
-		if(isHeroLocked(node.targetHero))
+		auto lockReason = getHeroLockedReason(node.targetHero);
+
+		if(lockReason != HeroLockedReason::NOT_LOCKED)
+		{
+#if AI_TRACE_LEVEL >= 1
+			logAi->trace("Hero %s is locked by STARTUP. Discarding %s", path.targetHero->name, path.toString());
+#endif
 			return true;
+		}
 	}
 
 	return false;
 }
 
+HeroLockedReason Nullkiller::getHeroLockedReason(const CGHeroInstance * hero) const
+{
+	auto found = lockedHeroes.find(hero);
+
+	return found != lockedHeroes.end() ? found->second : HeroLockedReason::NOT_LOCKED;
+}
+
 void Nullkiller::makeTurn()
 {
 	resetAiState();
@@ -149,7 +177,7 @@ void Nullkiller::makeTurn()
 		{
 			if(bestTask->hero)
 			{
-				activeHero = bestTask->hero.get();
+				setActive(bestTask->hero.get(), bestTask->tile);
 			}
 
 			bestTask->accept(ai.get());

+ 6 - 3
AI/Nullkiller/Engine/Nullkiller.h

@@ -34,6 +34,7 @@ class Nullkiller
 private:
 	std::unique_ptr<PriorityEvaluator> priorityEvaluator;
 	const CGHeroInstance * activeHero;
+	int3 targetTile;
 	std::map<const CGHeroInstance *, HeroLockedReason> lockedHeroes;
 
 public:
@@ -43,9 +44,11 @@ public:
 	Nullkiller();
 	void makeTurn();
 	bool isActive(const CGHeroInstance * hero) const { return activeHero == hero; }
-	bool isHeroLocked(const CGHeroInstance * hero) const { return vstd::contains(lockedHeroes, hero); }
-	HeroLockedReason getHeroLockedReason(const CGHeroInstance * hero) const { return isHeroLocked(hero) ? lockedHeroes.at(hero) : HeroLockedReason::NOT_LOCKED; }
-	void setActive(const CGHeroInstance * hero) { activeHero = hero; }
+	bool isHeroLocked(const CGHeroInstance * hero) const;
+	HeroPtr getActiveHero() { return activeHero; }
+	HeroLockedReason getHeroLockedReason(const CGHeroInstance * hero) const;
+	int3 getTargetTile() const { return targetTile; }
+	void setActive(const CGHeroInstance * hero, int3 tile) { activeHero = hero; targetTile = tile; }
 	void lockHero(const CGHeroInstance * hero, HeroLockedReason lockReason) { lockedHeroes[hero] = lockReason; }
 	void unlockHero(const CGHeroInstance * hero) { lockedHeroes.erase(hero); }
 	bool arePathHeroesLocked(const AIPath & path) const;

+ 9 - 0
AI/Nullkiller/FuzzyHelper.cpp

@@ -289,6 +289,15 @@ ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj, const VCAI * ai)
 		const CGTownInstance * cre = dynamic_cast<const CGTownInstance *>(obj);
 		return cre->getUpperArmy()->getArmyStrength();
 	}
+	case Obj::ARTIFACT:
+	case Obj::RESOURCE:
+	{
+		if(!vstd::contains(ai->alreadyVisited, obj))
+		{
+			return 0;
+		}
+		// passthrough
+	}
 	case Obj::MONSTER:
 	case Obj::HERO:
 	case Obj::GARRISON:

+ 1 - 1
AI/Nullkiller/Goals/ExecuteHeroChain.cpp

@@ -88,7 +88,7 @@ void ExecuteHeroChain::accept(VCAI * ai)
 		{
 			if(hero->movement)
 			{
-				ai->nullkiller->setActive(hero.get());
+				ai->nullkiller->setActive(hero.get(), node.coord);
 
 				if(node.specialAction)
 				{

+ 28 - 2
AI/Nullkiller/VCAI.cpp

@@ -652,8 +652,34 @@ void VCAI::showBlockingDialog(const std::string & text, const std::vector<Compon
 	if(selection) //select from multiple components -> take the last one (they're indexed [1-size])
 		sel = components.size();
 
-	if(!selection && cancel) //yes&no -> always answer yes, we are a brave AI :)
-		sel = 1;
+	if(!selection && cancel)
+	{
+		requestActionASAP([=]()
+		{
+			//yes&no -> always answer yes, we are a brave AI :)
+			auto answer = 1;
+			if(nullkiller)
+			{
+				auto hero = nullkiller->getActiveHero();
+				auto target = nullkiller->getTargetTile();
+
+				if(hero.validAndSet() && target.valid())
+				{
+					auto ratio = (float)fh->evaluateDanger(target, hero.get()) / (float)hero->getTotalStrength();
+					bool dangerUnknown = ratio == 0;
+					bool dangerTooHigh = ratio > (1 / SAFE_ATTACK_CONSTANT);
+
+					logAi->trace("Guarded object query hook: %s by %s danger ratio %f", target.toString(), hero.name, ratio);
+
+					if(text.find("guarded") >= 0 && (dangerUnknown || dangerTooHigh))
+						answer = 0; // no
+				}
+			}
+
+			answerQuery(askID, answer);
+		});
+		return;
+	}
 
 	// TODO: Find better way to understand it is Chest of Treasures
 	if(components.size() == 2 && components.front().id == Component::RESOURCE)