2018-12-01 10:30:37 +02:00
|
|
|
/*
|
|
|
|
* VisitObj.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 "Goals.h"
|
|
|
|
#include "../VCAI.h"
|
|
|
|
#include "../AIUtility.h"
|
|
|
|
#include "../AIhelper.h"
|
|
|
|
#include "../FuzzyHelper.h"
|
|
|
|
#include "../ResourceManager.h"
|
|
|
|
#include "../BuildingManager.h"
|
|
|
|
#include "../../../lib/StringConstants.h"
|
|
|
|
|
|
|
|
|
|
|
|
extern boost::thread_specific_ptr<CCallback> cb;
|
|
|
|
extern boost::thread_specific_ptr<VCAI> ai;
|
|
|
|
extern FuzzyHelper * fh;
|
|
|
|
|
|
|
|
using namespace Goals;
|
|
|
|
|
|
|
|
bool VisitObj::operator==(const VisitObj & other) const
|
|
|
|
{
|
|
|
|
return other.hero.h == hero.h && other.objid == objid;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string VisitObj::completeMessage() const
|
|
|
|
{
|
2023-03-09 15:36:46 +02:00
|
|
|
return "hero " + hero.get()->getNameTranslated() + " captured Object ID = " + std::to_string(objid);
|
2018-12-01 10:30:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TGoalVec VisitObj::getAllPossibleSubgoals()
|
|
|
|
{
|
|
|
|
TGoalVec goalList;
|
|
|
|
const CGObjectInstance * obj = cb->getObjInstance(ObjectInstanceID(objid));
|
|
|
|
if(!obj)
|
|
|
|
{
|
|
|
|
throw cannotFulfillGoalException("Object is missing - goal is invalid now!");
|
|
|
|
}
|
|
|
|
|
|
|
|
int3 pos = obj->visitablePos();
|
|
|
|
if(hero)
|
|
|
|
{
|
|
|
|
if(ai->isAccessibleForHero(pos, hero))
|
|
|
|
{
|
|
|
|
if(isSafeToVisit(hero, pos))
|
|
|
|
goalList.push_back(sptr(VisitObj(obj->id.getNum()).sethero(hero)));
|
|
|
|
else
|
2020-10-01 10:38:06 +02:00
|
|
|
goalList.push_back(sptr(GatherArmy((int)(fh->evaluateDanger(pos, hero.h) * SAFE_ATTACK_CONSTANT)).sethero(hero).setisAbstract(true)));
|
2018-12-01 10:30:37 +02:00
|
|
|
|
|
|
|
return goalList;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(auto potentialVisitor : cb->getHeroesInfo())
|
|
|
|
{
|
|
|
|
if(ai->isAccessibleForHero(pos, potentialVisitor))
|
|
|
|
{
|
|
|
|
if(isSafeToVisit(potentialVisitor, pos))
|
|
|
|
goalList.push_back(sptr(VisitObj(obj->id.getNum()).sethero(potentialVisitor)));
|
|
|
|
else
|
2020-10-01 10:38:06 +02:00
|
|
|
goalList.push_back(sptr(GatherArmy((int)(fh->evaluateDanger(pos, potentialVisitor) * SAFE_ATTACK_CONSTANT)).sethero(potentialVisitor).setisAbstract(true)));
|
2018-12-01 10:30:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!goalList.empty())
|
|
|
|
{
|
|
|
|
return goalList;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
goalList.push_back(sptr(ClearWayTo(pos)));
|
|
|
|
return goalList;
|
|
|
|
}
|
|
|
|
|
|
|
|
TSubgoal VisitObj::whatToDoToAchieve()
|
|
|
|
{
|
|
|
|
auto bestGoal = fh->chooseSolution(getAllPossibleSubgoals());
|
|
|
|
|
|
|
|
if(bestGoal->goalType == VISIT_OBJ && bestGoal->hero)
|
|
|
|
bestGoal->setisElementar(true);
|
|
|
|
|
|
|
|
return bestGoal;
|
|
|
|
}
|
|
|
|
|
2019-02-10 20:09:24 +02:00
|
|
|
VisitObj::VisitObj(int Objid)
|
|
|
|
: CGoal(VISIT_OBJ)
|
2018-12-01 10:30:37 +02:00
|
|
|
{
|
|
|
|
objid = Objid;
|
2019-02-10 20:09:24 +02:00
|
|
|
auto obj = ai->myCb->getObjInstance(ObjectInstanceID(objid));
|
|
|
|
if(obj)
|
|
|
|
tile = obj->visitablePos();
|
|
|
|
else
|
|
|
|
logAi->error("VisitObj constructed with invalid object instance %d", Objid);
|
|
|
|
|
2018-12-01 10:30:37 +02:00
|
|
|
priority = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VisitObj::fulfillsMe(TSubgoal goal)
|
|
|
|
{
|
|
|
|
if(goal->goalType == VISIT_TILE)
|
|
|
|
{
|
|
|
|
if (!hero || hero == goal->hero)
|
|
|
|
{
|
|
|
|
auto obj = cb->getObjInstance(ObjectInstanceID(objid));
|
|
|
|
if (obj && obj->visitablePos() == goal->tile) //object could be removed
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|