Преглед на файлове

Nullkiller: fix priorities after refactoring

Andrii Danylchenko преди 4 години
родител
ревизия
cebb5b296b

+ 2 - 2
AI/Nullkiller/AIUtility.h

@@ -36,9 +36,9 @@ extern const int GOLD_RESERVE;
 
 enum HeroRole
 {
-	SCOUT,
+	SCOUT = 0,
 
-	MAIN
+	MAIN = 1
 };
 
 //provisional class for AI to store a reference to an owned hero object

+ 2 - 2
AI/Nullkiller/ArmyManager.cpp

@@ -363,12 +363,12 @@ ArmyUpgradeInfo ArmyManager::calculateCreateresUpgrade(
 		{
 			SlotInfo upgradedArmy;
 
-			upgradedArmy.creature = upgrade.upgradedCreature;
+			upgradedArmy.creature = upgrade.upgradedCreature.toCreature();
 			upgradedArmy.count = upgrade.count;
 			upgradedArmy.power = evaluateStackPower(upgradedArmy.creature, upgradedArmy.count);
 
 			auto slotToReplace = std::find_if(result.resultingArmy.begin(), result.resultingArmy.end(), [&](const SlotInfo & slot) -> bool {
-				return slot.count == upgradedArmy.count && slot.creature == upgrade.initialCreature;
+				return slot.count == upgradedArmy.count && slot.creature->idNumber == upgrade.initialCreature;
 			});
 
 			resourcesLeft -= upgrade.cost;

+ 15 - 16
AI/Nullkiller/Behaviors/CompleteQuestBehavior.cpp

@@ -129,10 +129,12 @@ TGoalVec CompleteQuest::missionArt() const
 	if(!solutions.empty())
 		return solutions;
 
-	/*for(auto art : q.quest->m5arts)
+	CaptureObjectsBehavior findArts;
+
+	for(auto art : q.quest->m5arts)
 	{
-		solutions.push_back(sptr(GetArtOfType(art))); //TODO: transport?
-	}*/
+		solutions.push_back(sptr(CaptureObjectsBehavior().ofType(Obj::ARTIFACT, art)));
+	}
 
 	return solutions;
 }
@@ -223,21 +225,18 @@ TGoalVec CompleteQuest::missionDestroyObj() const
 	if(!obj)
 		return CaptureObjectsBehavior(q.obj).decompose();
 
-	if(obj->ID == Obj::HERO)
-	{
-		auto relations = cb->getPlayerRelations(ai->playerID, obj->tempOwner);
+	auto relations = cb->getPlayerRelations(ai->playerID, obj->tempOwner);
 
-		//if(relations == PlayerRelations::SAME_PLAYER)
-		//{
-		//	auto heroToProtect = cb->getHero(obj->id);
+	//if(relations == PlayerRelations::SAME_PLAYER)
+	//{
+	//	auto heroToProtect = cb->getHero(obj->id);
 
-		//	//solutions.push_back(sptr(GatherArmy().sethero(heroToProtect)));
-		//}
-		//else 
-		if(relations == PlayerRelations::ENEMIES)
-		{
-			return CaptureObjectsBehavior(obj).decompose();
-		}
+	//	//solutions.push_back(sptr(GatherArmy().sethero(heroToProtect)));
+	//}
+	//else 
+	if(relations == PlayerRelations::ENEMIES)
+	{
+		return CaptureObjectsBehavior(obj).decompose();
 	}
 
 	return TGoalVec();

+ 2 - 7
AI/Nullkiller/Behaviors/DefenceBehavior.cpp

@@ -35,14 +35,9 @@ Goals::TGoalVec DefenceBehavior::decompose() const
 {
 	Goals::TGoalVec tasks;
 		
-	auto heroes = cb->getHeroesInfo();
-
-	if(heroes.size())
+	for(auto town : cb->getTownsInfo())
 	{
-		for(auto town : cb->getTownsInfo())
-		{
-			evaluateDefence(tasks, town);
-		}
+		evaluateDefence(tasks, town);
 	}
 
 	return tasks;

+ 5 - 4
AI/Nullkiller/Engine/PriorityEvaluator.cpp

@@ -474,7 +474,7 @@ public:
 		auto army = path.heroArmy;
 
 		vstd::amax(evaluationContext.armyLossPersentage, path.getTotalArmyLoss() / (double)path.getHeroStrength());
-		vstd::amax(evaluationContext.heroRole, ai->ah->getHeroRole(heroPtr));
+		evaluationContext.heroRole = ai->ah->getHeroRole(heroPtr);
 		evaluationContext.goldReward += getGoldReward(target, hero);
 		evaluationContext.armyReward += getArmyReward(target, hero, army, checkGold);
 		evaluationContext.skillReward += getSkillReward(target, hero, evaluationContext.heroRole);
@@ -604,17 +604,18 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
 	}
 	assert(result >= 0);
 
-#ifdef VCMI_TRACE_PATHFINDER
-	logAi->trace("Evaluated %s, loss: %f, turns main: %f, scout: %f, gold: %d, cost: %d, army gain: %d, danger: %d, role: %s, strategical value: %f, cwr: %f, result %f",
+#ifdef AI_TRACE_LEVEL >= 1
+	logAi->trace("Evaluated %s, loss: %f, turn: %d, turns main: %f, scout: %f, gold: %d, cost: %d, army gain: %d, danger: %d, role: %s, strategical value: %f, cwr: %f, result %f",
 		task->toString(),
 		evaluationContext.armyLossPersentage,
+		(int)evaluationContext.turn,
 		evaluationContext.movementCostByRole[HeroRole::MAIN],
 		evaluationContext.movementCostByRole[HeroRole::SCOUT],
 		evaluationContext.goldReward,
 		evaluationContext.goldCost,
 		evaluationContext.armyReward,
 		evaluationContext.danger,
-		evaluationContext.heroRole ? "scout" : "main",
+		evaluationContext.heroRole == HeroRole::MAIN ? "main" : "scout",
 		evaluationContext.strategicalValue,
 		evaluationContext.closestWayRatio,
 		result);

+ 12 - 12
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -214,7 +214,7 @@ void AINodeStorage::commit(
 	destination->theNodeBefore = source->theNodeBefore;
 	destination->chainOther = nullptr;
 
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 	logAi->trace(
 		"Commited %s -> %s, cost: %f, turn: %s, mp: %d, hero: %s, mask: %x, army: %lld",
 		source->coord.toString(),
@@ -422,7 +422,7 @@ void AINodeStorage::calculateHeroChain(
 			|| (node->action == CGPathNode::ENodeAction::UNKNOWN && node->actor->hero)
 			|| (node->actor->chainMask & srcNode->actor->chainMask) != 0)
 		{
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 			logAi->trace(
 				"Skip exchange %s[%x] -> %s[%x] at %s because of %s",
 				node->actor->toString(),
@@ -439,7 +439,7 @@ void AINodeStorage::calculateHeroChain(
 			continue;
 		}
 
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 		logAi->trace(
 			"Thy exchange %s[%x] -> %s[%x] at %s",
 			node->actor->toString(),
@@ -464,7 +464,7 @@ void AINodeStorage::calculateHeroChain(
 		&& (other->armyLoss == 0 || other->armyLoss < other->actor->armyValue)
 		&& carrier->actor->canExchange(other->actor))
 	{
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 		logAi->trace(
 			"Exchange allowed %s[%x] -> %s[%x] at %s",
 			other->actor->toString(),
@@ -481,7 +481,7 @@ void AINodeStorage::calculateHeroChain(
 
 			if(hasLessMp && hasLessExperience)
 			{
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 				logAi->trace("Exchange at %s is ineficient. Blocked.", carrier->coord.toString());
 #endif
 				return;
@@ -505,7 +505,7 @@ void AINodeStorage::addHeroChain(const std::vector<ExchangeCandidate> & result)
 
 		if(!chainNodeOptional)
 		{
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 			logAi->trace("Exchange at %s can not allocate node. Blocked.", carrier->coord.toString());
 #endif
 			continue;
@@ -515,7 +515,7 @@ void AINodeStorage::addHeroChain(const std::vector<ExchangeCandidate> & result)
 
 		if(exchangeNode->action != CGPathNode::ENodeAction::UNKNOWN)
 		{
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 			logAi->trace("Exchange at %s node is already in use. Blocked.", carrier->coord.toString());
 #endif
 			continue;
@@ -523,7 +523,7 @@ void AINodeStorage::addHeroChain(const std::vector<ExchangeCandidate> & result)
 		
 		if(exchangeNode->turns != 0xFF && exchangeNode->cost < chainInfo.cost)
 		{
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 			logAi->trace(
 				"Exchange at %s is is not effective enough. %f < %f", 
 				exchangeNode->coord.toString(), 
@@ -544,7 +544,7 @@ void AINodeStorage::addHeroChain(const std::vector<ExchangeCandidate> & result)
 		exchangeNode->chainOther = other;
 		exchangeNode->armyLoss = chainInfo.armyLoss;
 
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 		logAi->trace(
 			"Chain accepted at %s %s -> %s, mask %x, cost %f, turn: %s, mp: %d, army %i", 
 			exchangeNode->coord.toString(), 
@@ -858,7 +858,7 @@ void AINodeStorage::calculateTownPortalTeleportations(std::vector<CGPathNode *>
 
 				if(nodeOptional)
 				{
-#if AI_TRACE_LEVEL >= 1
+#if PATHFINDER_TRACE_LEVEL >= 1
 					logAi->trace("Adding town portal node at %s", targetTown->name);
 #endif
 					initialNodes.push_back(nodeOptional.get());
@@ -897,7 +897,7 @@ bool AINodeStorage::hasBetterChain(
 		{
 			if(node.cost < candidateNode->cost)
 			{
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 				logAi->trace(
 					"Block ineficient battle move %s->%s, hero: %s[%X], army %lld, mp diff: %i",
 					source->coord.toString(),
@@ -921,7 +921,7 @@ bool AINodeStorage::hasBetterChain(
 		if(nodeArmyValue > candidateArmyValue
 			&& node.cost <= candidateNode->cost)
 		{
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 			logAi->trace(
 				"Block ineficient move because of stronger army %s->%s, hero: %s[%X], army %lld, mp diff: %i",
 				source->coord.toString(),

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

@@ -10,8 +10,8 @@
 
 #pragma once
 
-#define VCMI_TRACE_PATHFINDER 1
-#define AI_TRACE_LEVEL 1
+#define PATHFINDER_TRACE_LEVEL 1
+#define AI_TRACE_LEVEL 2
 
 #include "../../../lib/CPathfinder.h"
 #include "../../../lib/mapObjects/CGHeroInstance.h"

+ 2 - 1
AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp

@@ -36,7 +36,8 @@ namespace AIPathfinding
 			return dynamic_cast<const IQuestObject *>(questInfo.obj)->checkQuest(node->actor->hero);
 		}
 
-		return questInfo.quest->checkQuest(node->actor->hero);
+		return questInfo.quest->progress == CQuest::NOT_ACTIVE 
+			|| questInfo.quest->checkQuest(node->actor->hero);
 	}
 
 	Goals::TSubgoal QuestAction::decompose(const CGHeroInstance * hero) const

+ 2 - 2
AI/Nullkiller/Pathfinding/Actors.cpp

@@ -172,7 +172,7 @@ bool HeroExchangeMap::canExchange(const ChainActor * other)
 			if(!resources.canAfford(actor->armyCost + other->armyCost))
 			{
 				result = false;
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 				logAi->trace(
 					"Can not afford exchange because of total cost %s but we have %s",
 					(actor->armyCost + other->armyCost).toString(),
@@ -191,7 +191,7 @@ bool HeroExchangeMap::canExchange(const ChainActor * other)
 			if(other->creatureSet->Slots().size())
 				reinforcment += ai->ah->howManyReinforcementsCanGet(actor->creatureSet, other->creatureSet);
 
-#if AI_TRACE_LEVEL >= 2
+#if PATHFINDER_TRACE_LEVEL >= 2
 			logAi->trace(
 				"Exchange %s->%s reinforcement: %d, %f%%",
 				actor->toString(),

+ 2 - 2
AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp

@@ -37,7 +37,7 @@ namespace AIPathfinding
 
 			if(virtualBoat && tryEmbarkVirtualBoat(destination, source, virtualBoat))
 			{
-#ifdef VCMI_TRACE_PATHFINDER
+#if PATHFINDER_TRACE_LEVEL >= 1
 				logAi->trace("Embarking to virtual boat while moving %s -> %s!", source.coord.toString(), destination.coord.toString());
 #endif
 			}
@@ -138,7 +138,7 @@ namespace AIPathfinding
 				}
 				else
 				{
-#ifdef VCMI_TRACE_PATHFINDER
+#if PATHFINDER_TRACE_LEVEL >= 1
 					logAi->trace(
 						"Special transition node already allocated. Blocked moving %s -> %s",
 						source.coord.toString(),

+ 9 - 4
AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp

@@ -102,6 +102,11 @@ namespace AIPathfinding
 			auto questObj = dynamic_cast<const IQuestObject *>(destination.nodeObject);
 			auto nodeHero = pathfinderHelper->hero;
 
+			if(destination.nodeObject->ID == Obj::QUEST_GUARD && questObj->quest->missionType == CQuest::MISSION_NONE)
+			{
+				return false;
+			}
+
 			if(!destination.nodeObject->wasVisited(nodeHero->tempOwner)
 				|| !questObj->checkQuest(nodeHero))
 			{
@@ -154,7 +159,7 @@ namespace AIPathfinding
 
 		if(guardsAlreadyBypassed && srcNode->actor->allowBattle)
 		{
-#ifdef VCMI_TRACE_PATHFINDER
+#if PATHFINDER_TRACE_LEVEL >= 1
 			logAi->trace(
 				"Bypass guard at destination while moving %s -> %s",
 				source.coord.toString(),
@@ -182,7 +187,7 @@ namespace AIPathfinding
 
 		if(!battleNodeOptional)
 		{
-#ifdef VCMI_TRACE_PATHFINDER
+#if PATHFINDER_TRACE_LEVEL >= 1
 			logAi->trace(
 				"Can not allocate battle node while moving %s -> %s",
 				source.coord.toString(),
@@ -195,7 +200,7 @@ namespace AIPathfinding
 
 		if(battleNode->locked)
 		{
-#ifdef VCMI_TRACE_PATHFINDER
+#if PATHFINDER_TRACE_LEVEL >= 1
 			logAi->trace(
 				"Block bypass guard at destination while moving %s -> %s",
 				source.coord.toString(),
@@ -222,7 +227,7 @@ namespace AIPathfinding
 
 			battleNode->specialAction = std::make_shared<BattleAction>(destination.coord);
 
-#ifdef VCMI_TRACE_PATHFINDER
+#if PATHFINDER_TRACE_LEVEL >= 1
 			logAi->trace(
 				"Begin bypass guard at destination with danger %s while moving %s -> %s",
 				std::to_string(danger),

+ 1 - 1
AI/Nullkiller/Pathfinding/Rules/AIMovementToDestinationRule.cpp

@@ -37,7 +37,7 @@ namespace AIPathfinding
 
 		if(blocker == BlockingReason::SOURCE_GUARDED && nodeStorage->getAINode(source.node)->actor->allowBattle)
 		{
-#ifdef VCMI_TRACE_PATHFINDER
+#if PATHFINDER_TRACE_LEVEL >= 1
 			logAi->trace(
 				"Bypass src guard while moving from %s to %s",
 				source.coord.toString(),

+ 2 - 1
AI/Nullkiller/Pathfinding/Rules/AIPreviousNodeRule.cpp

@@ -27,7 +27,8 @@ namespace AIPathfinding
 		{
 			// we can not directly bypass objects, we need to interact with them first
 			destination.node->theNodeBefore = source.node;
-#ifdef VCMI_TRACE_PATHFINDER
+
+#if PATHFINDER_TRACE_LEVEL >= 1
 			logAi->trace(
 				"Link src node %s to destination node %s while bypassing visitable obj",
 				source.coord.toString(),

+ 18 - 11
AI/Nullkiller/VCAI.cpp

@@ -569,12 +569,11 @@ void VCAI::showBlockingDialog(const std::string & text, const std::vector<Compon
 {
 	LOG_TRACE_PARAMS(logAi, "text '%s', askID '%i', soundID '%i', selection '%i', cancel '%i'", text % askID % soundID % selection % cancel);
 	NET_EVENT_HANDLER;
-	int sel = 0;
 	status.addQuery(askID, boost::str(boost::format("Blocking dialog query with %d components - %s")
 									  % components.size() % text));
 
-	if(selection) //select from multiple components -> take the last one (they're indexed [1-size])
-		sel = components.size();
+	auto hero = nullkiller->getActiveHero();
+	auto target = nullkiller->getTargetTile();
 
 	if(!selection && cancel)
 	{
@@ -582,8 +581,6 @@ void VCAI::showBlockingDialog(const std::string & text, const std::vector<Compon
 		{
 			//yes&no -> always answer yes, we are a brave AI :)
 			auto answer = 1;
-			auto hero = nullkiller->getActiveHero();
-			auto target = nullkiller->getTargetTile();
 			auto objects = cb->getVisitableObjs(target);
 
 			if(hero.validAndSet() && target.valid() && objects.size())
@@ -608,14 +605,21 @@ void VCAI::showBlockingDialog(const std::string & text, const std::vector<Compon
 		return;
 	}
 
-	// TODO: Find better way to understand it is Chest of Treasures
-	if(components.size() == 2 && components.front().id == Component::RESOURCE)
-	{
-		sel = 1; // for now lets pick gold from a chest.
-	}
-
 	requestActionASAP([=]()
 	{
+		int sel = 0;
+
+		if(selection) //select from multiple components -> take the last one (they're indexed [1-size])
+			sel = components.size();
+
+		// TODO: Find better way to understand it is Chest of Treasures
+		if(components.size() == 2
+			&& components.front().id == Component::RESOURCE
+			&& ah->getHeroRole(hero) != HeroRole::MAIN)
+		{
+			sel = 1; // for now lets pick gold from a chest.
+		}
+
 		answerQuery(askID, sel);
 	});
 }
@@ -2026,6 +2030,9 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 		break;
 	case Obj::TREE_OF_KNOWLEDGE:
 	{
+		if(ai->ah->getHeroRole(h) == HeroRole::SCOUT)
+			return false;
+
 		TResources myRes = cb->getResourceAmount();
 		if(myRes[Res::GOLD] < 2000 || myRes[Res::GEMS] < 10)
 			return false;