| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 | /** CaptureObjectsBehavior.cpp, part of VCMI engine** Authors: listed in file AUTHORS in main folder** License: GNU General Public License v2.0 or later* Full text of license available in license.txt file, in main folder**/#include "StdInc.h"#include "../VCAI.h"#include "../Engine/Nullkiller.h"#include "../AIhelper.h"#include "../Goals/ExecuteHeroChain.h"#include "CaptureObjectsBehavior.h"#include "../AIUtility.h"#include "lib/mapping/CMap.h" //for victory conditions#include "lib/CPathfinder.h"extern boost::thread_specific_ptr<CCallback> cb;extern boost::thread_specific_ptr<VCAI> ai;extern FuzzyHelper * fh;using namespace Goals;std::string CaptureObjectsBehavior::toString() const{	return "Capture objects";}Goals::TGoalVec CaptureObjectsBehavior::getTasks(){	Goals::TGoalVec tasks;	auto captureObjects = [&](const std::vector<const CGObjectInstance*> & objs) -> void{		if(objs.empty())		{			return;		}		logAi->trace("Scanning objects, count %d", objs.size());		for(auto objToVisit : objs)		{			#ifdef VCMI_TRACE_PATHFINDER			logAi->trace("Checking object %s, %s", objToVisit->getObjectName(), objToVisit->visitablePos().toString());#endif			if(!shouldVisitObject(objToVisit))				continue;			const int3 pos = objToVisit->visitablePos();			auto paths = ai->ah->getPathsToTile(pos);			std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;			std::shared_ptr<ExecuteHeroChain> closestWay;					#ifdef VCMI_TRACE_PATHFINDER			logAi->trace("Found %d paths", paths.size());#endif			for(auto & path : paths)			{#ifdef VCMI_TRACE_PATHFINDER				logAi->trace("Path found %s", path.toString());#endif				if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))				{#ifdef VCMI_TRACE_PATHFINDER					logAi->trace("Ignore path. Target hero can be killed by enemy");#endif					continue;				}				if(!shouldVisit(path.targetHero, objToVisit))					continue;				auto hero = path.targetHero;				auto danger = path.getTotalDanger(hero);				auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);				#ifdef VCMI_TRACE_PATHFINDER				logAi->trace(					"It is %s to visit %s by %s with army %lld, danger %lld and army loss %lld", 					isSafe ? "safe" : "not safe",					objToVisit->instanceName, 					hero->name,					path.getHeroStrength(),					danger,					path.armyLoss);#endif				if(isSafe)				{					auto newWay = std::make_shared<ExecuteHeroChain>(path, objToVisit);					waysToVisitObj.push_back(newWay);					if(!closestWay || closestWay->evaluationContext.movementCost > newWay->evaluationContext.movementCost)						closestWay = newWay;				}			}			if(waysToVisitObj.empty())				continue;			for(auto way : waysToVisitObj)			{				way->evaluationContext.closestWayRatio					= way->evaluationContext.movementCost / closestWay->evaluationContext.movementCost;				tasks.push_back(sptr(*way));			}		}	};	if(specificObjects)	{		captureObjects(objectsToCapture);	}	else	{		captureObjects(std::vector<const CGObjectInstance*>(ai->visitableObjs.begin(), ai->visitableObjs.end()));	}	return tasks;}bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const{	const CGObjectInstance* objInstance = obj;	if(!objInstance)		return false;	if(objectTypes.size() && !vstd::contains(objectTypes, objInstance->ID.num))	{		return false;	}	if(objectSubTypes.size() && !vstd::contains(objectSubTypes, objInstance->subID))	{		return false;	}	const int3 pos = objInstance->visitablePos();	if(vstd::contains(ai->alreadyVisited, objInstance))	{		return false;	}	auto playerRelations = cb->getPlayerRelations(ai->playerID, objInstance->tempOwner);	if(playerRelations != PlayerRelations::ENEMIES && !isWeeklyRevisitable(objInstance))	{		return false;	}	//it may be hero visiting this obj	//we don't try visiting object on which allied or owned hero stands	// -> it will just trigger exchange windows and AI will be confused that obj behind doesn't get visited	const CGObjectInstance * topObj = cb->getTopObj(pos);	if(!topObj)		return false; // partly visible obj but its visitable pos is not visible.	if(topObj->ID == Obj::HERO && cb->getPlayerRelations(ai->playerID, topObj->tempOwner) != PlayerRelations::ENEMIES)		return false;	else		return true; //all of the following is met}
 |