mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-26 22:57:00 +02:00
AI pathfinding: buy boat
This commit is contained in:
parent
32c480c33d
commit
72aff02418
@ -29,11 +29,11 @@ bool AIhelper::notifyGoalCompleted(Goals::TSubgoal goal)
|
|||||||
return resourceManager->notifyGoalCompleted(goal);
|
return resourceManager->notifyGoalCompleted(goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIhelper::setCB(CPlayerSpecificInfoCallback * CB)
|
void AIhelper::init(CPlayerSpecificInfoCallback * CB)
|
||||||
{
|
{
|
||||||
resourceManager->setCB(CB);
|
resourceManager->init(CB);
|
||||||
buildingManager->setCB(CB);
|
buildingManager->init(CB);
|
||||||
pathfindingManager->setCB(CB);
|
pathfindingManager->init(CB);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIhelper::setAI(VCAI * AI)
|
void AIhelper::setAI(VCAI * AI)
|
||||||
|
@ -63,7 +63,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool notifyGoalCompleted(Goals::TSubgoal goal);
|
bool notifyGoalCompleted(Goals::TSubgoal goal);
|
||||||
|
|
||||||
void setCB(CPlayerSpecificInfoCallback * CB) override;
|
void init(CPlayerSpecificInfoCallback * CB) override;
|
||||||
void setAI(VCAI * AI) override;
|
void setAI(VCAI * AI) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ bool BuildingManager::tryBuildNextStructure(const CGTownInstance * t, std::vecto
|
|||||||
return false; //Nothing to build
|
return false; //Nothing to build
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildingManager::setCB(CPlayerSpecificInfoCallback * CB)
|
void BuildingManager::init(CPlayerSpecificInfoCallback * CB)
|
||||||
{
|
{
|
||||||
cb = CB;
|
cb = CB;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ class DLL_EXPORT IBuildingManager //: public: IAbstractManager
|
|||||||
{ //info about town development
|
{ //info about town development
|
||||||
public:
|
public:
|
||||||
virtual ~IBuildingManager() = default;
|
virtual ~IBuildingManager() = default;
|
||||||
virtual void setCB(CPlayerSpecificInfoCallback * CB) = 0;
|
virtual void init(CPlayerSpecificInfoCallback * CB) = 0;
|
||||||
virtual void setAI(VCAI * AI) = 0;
|
virtual void setAI(VCAI * AI) = 0;
|
||||||
|
|
||||||
virtual bool getBuildingOptions(const CGTownInstance * t) = 0;
|
virtual bool getBuildingOptions(const CGTownInstance * t) = 0;
|
||||||
@ -69,6 +69,6 @@ private:
|
|||||||
std::vector<PotentialBuilding> immediateBuildings; //what we can build right now in current town
|
std::vector<PotentialBuilding> immediateBuildings; //what we can build right now in current town
|
||||||
std::vector<PotentialBuilding> expensiveBuildings; //what we coudl build but can't afford
|
std::vector<PotentialBuilding> expensiveBuildings; //what we coudl build but can't afford
|
||||||
|
|
||||||
void setCB(CPlayerSpecificInfoCallback * CB) override;
|
void init(CPlayerSpecificInfoCallback * CB) override;
|
||||||
void setAI(VCAI * AI) override;
|
void setAI(VCAI * AI) override;
|
||||||
};
|
};
|
||||||
|
@ -76,18 +76,14 @@ armyStructure evaluateArmyStructure(const CArmedInstance * army)
|
|||||||
return as;
|
return as;
|
||||||
}
|
}
|
||||||
|
|
||||||
float HeroMovementGoalEngineBase::calculateTurnDistanceInputValue(const CGHeroInstance * h, int3 tile) const
|
float HeroMovementGoalEngineBase::calculateTurnDistanceInputValue(const Goals::AbstractGoal & goal) const
|
||||||
{
|
{
|
||||||
float turns = 0.0f;
|
if(goal.evaluationContext.movementCost != 0)
|
||||||
float distance = distanceToTile(h, tile);
|
|
||||||
if(distance)
|
|
||||||
{
|
{
|
||||||
if(distance < h->movement) //we can move there within one turn
|
return goal.evaluationContext.movementCost / (float)goal.hero->maxMovePoints(true);
|
||||||
turns = (fl::scalar)distance / h->movement;
|
|
||||||
else
|
|
||||||
turns = 1 + (fl::scalar)(distance - h->movement) / h->maxMovePoints(true); //bool on land?
|
|
||||||
}
|
}
|
||||||
return turns;
|
|
||||||
|
return distanceToTile(goal.hero.h, goal.tile) / (float)goal.hero->maxMovePoints(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TacticalAdvantageEngine::TacticalAdvantageEngine()
|
TacticalAdvantageEngine::TacticalAdvantageEngine()
|
||||||
@ -276,8 +272,8 @@ HeroMovementGoalEngineBase::HeroMovementGoalEngineBase()
|
|||||||
|
|
||||||
turnDistance->addTerm(new fl::Ramp("SHORT", 0.5, 0));
|
turnDistance->addTerm(new fl::Ramp("SHORT", 0.5, 0));
|
||||||
turnDistance->addTerm(new fl::Triangle("MEDIUM", 0.1, 0.8));
|
turnDistance->addTerm(new fl::Triangle("MEDIUM", 0.1, 0.8));
|
||||||
turnDistance->addTerm(new fl::Ramp("LONG", 0.5, 3));
|
turnDistance->addTerm(new fl::Ramp("LONG", 0.5, 10));
|
||||||
turnDistance->setRange(0.0, 3.0);
|
turnDistance->setRange(0.0, 10.0);
|
||||||
|
|
||||||
missionImportance->addTerm(new fl::Ramp("LOW", 2.5, 0));
|
missionImportance->addTerm(new fl::Ramp("LOW", 2.5, 0));
|
||||||
missionImportance->addTerm(new fl::Triangle("MEDIUM", 2, 3));
|
missionImportance->addTerm(new fl::Triangle("MEDIUM", 2, 3));
|
||||||
@ -319,7 +315,7 @@ HeroMovementGoalEngineBase::HeroMovementGoalEngineBase()
|
|||||||
|
|
||||||
void HeroMovementGoalEngineBase::setSharedFuzzyVariables(Goals::AbstractGoal & goal)
|
void HeroMovementGoalEngineBase::setSharedFuzzyVariables(Goals::AbstractGoal & goal)
|
||||||
{
|
{
|
||||||
float turns = calculateTurnDistanceInputValue(goal.hero.h, goal.tile);
|
float turns = calculateTurnDistanceInputValue(goal);
|
||||||
float missionImportanceData = 0;
|
float missionImportanceData = 0;
|
||||||
if(vstd::contains(ai->lockedHeroes, goal.hero))
|
if(vstd::contains(ai->lockedHeroes, goal.hero))
|
||||||
missionImportanceData = ai->lockedHeroes[goal.hero]->priority;
|
missionImportanceData = ai->lockedHeroes[goal.hero]->priority;
|
||||||
|
@ -52,7 +52,7 @@ protected:
|
|||||||
fl::OutputVariable * value;
|
fl::OutputVariable * value;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float calculateTurnDistanceInputValue(const CGHeroInstance * h, int3 tile) const;
|
float calculateTurnDistanceInputValue(const Goals::AbstractGoal & goal) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VisitTileEngine : public HeroMovementGoalEngineBase
|
class VisitTileEngine : public HeroMovementGoalEngineBase
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "FuzzyHelper.h"
|
#include "FuzzyHelper.h"
|
||||||
|
|
||||||
#include "../../lib/mapObjects/CommonConstructors.h"
|
#include "../../lib/mapObjects/CommonConstructors.h"
|
||||||
|
#include "Goals.h"
|
||||||
#include "VCAI.h"
|
#include "VCAI.h"
|
||||||
|
|
||||||
FuzzyHelper * fh;
|
FuzzyHelper * fh;
|
||||||
@ -79,6 +80,19 @@ float FuzzyHelper::evaluate(Goals::VisitTile & g)
|
|||||||
{
|
{
|
||||||
return visitTileEngine.evaluate(g);
|
return visitTileEngine.evaluate(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float FuzzyHelper::evaluate(Goals::BuildBoat & g)
|
||||||
|
{
|
||||||
|
const float buildBoatPenalty = 0.25;
|
||||||
|
|
||||||
|
if(!g.parent)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g.parent->accept(this) - buildBoatPenalty;
|
||||||
|
}
|
||||||
|
|
||||||
float FuzzyHelper::evaluate(Goals::VisitObj & g)
|
float FuzzyHelper::evaluate(Goals::VisitObj & g)
|
||||||
{
|
{
|
||||||
return visitObjEngine.evaluate(g);
|
return visitObjEngine.evaluate(g);
|
||||||
@ -90,8 +104,7 @@ float FuzzyHelper::evaluate(Goals::VisitHero & g)
|
|||||||
return -100; //hero died in the meantime
|
return -100; //hero died in the meantime
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto dummyGoal = Goals::VisitTile(obj->visitablePos()).sethero(g.hero).setisAbstract(g.isAbstract);
|
g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).accept(this));
|
||||||
g.setpriority(dummyGoal.accept(this));
|
|
||||||
}
|
}
|
||||||
return g.priority;
|
return g.priority;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ public:
|
|||||||
float evaluate(Goals::CollectRes & g);
|
float evaluate(Goals::CollectRes & g);
|
||||||
float evaluate(Goals::Build & g);
|
float evaluate(Goals::Build & g);
|
||||||
float evaluate(Goals::BuyArmy & g);
|
float evaluate(Goals::BuyArmy & g);
|
||||||
|
float evaluate(Goals::BuildBoat & g);
|
||||||
float evaluate(Goals::GatherArmy & g);
|
float evaluate(Goals::GatherArmy & g);
|
||||||
float evaluate(Goals::ClearWayTo & g);
|
float evaluate(Goals::ClearWayTo & g);
|
||||||
float evaluate(Goals::Invalid & g);
|
float evaluate(Goals::Invalid & g);
|
||||||
|
@ -115,70 +115,94 @@ std::string Goals::AbstractGoal::name() const //TODO: virtualize
|
|||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Goals::AbstractGoal::operator==(AbstractGoal & g)
|
bool Goals::BuildBoat::operator==(const BuildBoat & other) const
|
||||||
{
|
{
|
||||||
/*this operator checks if goals are EQUIVALENT, ie. if they represent same objective
|
return shipyard->o->id == other.shipyard->o->id;
|
||||||
it does not not check isAbstract or isElementar, as this is up to VCAI decomposition logic
|
}
|
||||||
*/
|
|
||||||
if(g.goalType != goalType)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
switch(goalType)
|
bool Goals::Explore::operator==(const Explore & other) const
|
||||||
{
|
{
|
||||||
//no parameters
|
return other.hero.h == hero.h;
|
||||||
case INVALID:
|
}
|
||||||
case WIN:
|
|
||||||
case DO_NOT_LOSE:
|
|
||||||
case RECRUIT_HERO: //overloaded
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//assigned to hero, no parameters
|
bool Goals::Conquer::operator==(const Conquer & other) const
|
||||||
case CONQUER:
|
{
|
||||||
case EXPLORE:
|
return other.hero.h == hero.h;
|
||||||
case BOOST_HERO:
|
}
|
||||||
return g.hero.h == hero.h; //how comes HeroPtrs are equal for different heroes?
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GATHER_ARMY: //actual value is indifferent
|
bool Goals::GatherArmy::operator==(const GatherArmy & other) const
|
||||||
return (g.hero.h == hero.h || town == g.town); //TODO: gather army for town maybe?
|
{
|
||||||
break;
|
return other.hero.h == hero.h || town == other.town;
|
||||||
|
}
|
||||||
|
|
||||||
//assigned hero and tile
|
bool Goals::BuyArmy::operator==(const BuyArmy & other) const
|
||||||
case VISIT_TILE:
|
{
|
||||||
case CLEAR_WAY_TO:
|
return town == other.town;
|
||||||
case DIG_AT_TILE:
|
}
|
||||||
return (g.hero.h == hero.h && g.tile == tile);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//assigned hero and object
|
bool Goals::BoostHero::operator==(const BoostHero & other) const
|
||||||
case VISIT_OBJ:
|
{
|
||||||
case FIND_OBJ: //TODO: use subtype?
|
return other.hero.h == hero.h;
|
||||||
case VISIT_HERO:
|
}
|
||||||
case GET_ART_TYPE:
|
|
||||||
return (g.hero.h == hero.h && g.objid == objid);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BUILD_STRUCTURE:
|
bool Goals::BuildThis::operator==(const BuildThis & other) const
|
||||||
return (town == g.town && bid == g.bid); //build specific structure in specific town
|
{
|
||||||
break;
|
return town == other.town && bid == other.bid;
|
||||||
|
}
|
||||||
|
|
||||||
case BUY_ARMY:
|
bool Goals::CollectRes::operator==(const CollectRes & other) const
|
||||||
return town == g.town;
|
{
|
||||||
|
return resID == other.resID;
|
||||||
|
}
|
||||||
|
|
||||||
//no check atm
|
bool Goals::Trade::operator==(const Trade & other) const
|
||||||
case COLLECT_RES:
|
{
|
||||||
case TRADE: //TODO
|
return resID == other.resID;
|
||||||
return (resID == g.resID); //every hero may collect resources
|
}
|
||||||
break;
|
|
||||||
case BUILD: //abstract build is indentical, TODO: consider building anything in town
|
bool Goals::GatherTroops::operator==(const GatherTroops & other) const
|
||||||
return true;
|
{
|
||||||
break;
|
return objid == other.objid;
|
||||||
case GATHER_TROOPS:
|
}
|
||||||
case ISSUE_COMMAND:
|
|
||||||
default:
|
bool Goals::VisitObj::operator==(const VisitObj & other) const
|
||||||
return false;
|
{
|
||||||
}
|
return other.hero.h == hero.h && other.objid == objid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Goals::FindObj::operator==(const FindObj & other) const
|
||||||
|
{
|
||||||
|
return other.hero.h == hero.h && other.objid == objid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Goals::VisitHero::operator==(const VisitHero & other) const
|
||||||
|
{
|
||||||
|
return other.hero.h == hero.h && other.objid == objid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Goals::GetArtOfType::operator==(const GetArtOfType & other) const
|
||||||
|
{
|
||||||
|
return other.hero.h == hero.h && other.objid == objid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Goals::VisitTile::operator==(const VisitTile & other) const
|
||||||
|
{
|
||||||
|
return other.hero.h == hero.h && other.tile == tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Goals::ClearWayTo::operator==(const ClearWayTo & other) const
|
||||||
|
{
|
||||||
|
return other.hero.h == hero.h && other.tile == tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Goals::DigAtTile::operator==(const DigAtTile & other) const
|
||||||
|
{
|
||||||
|
return other.hero.h == hero.h && other.tile == tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Goals::AbstractGoal::operator==(const AbstractGoal & g) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Goals::AbstractGoal::operator<(AbstractGoal & g) //for std::unique
|
bool Goals::AbstractGoal::operator<(AbstractGoal & g) //for std::unique
|
||||||
@ -263,14 +287,6 @@ namespace Goals
|
|||||||
return get() < rhs.get(); //compae by value
|
return get() < rhs.get(); //compae by value
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuyArmy::operator==(AbstractGoal & g)
|
|
||||||
{
|
|
||||||
if (g.goalType != goalType)
|
|
||||||
return false;
|
|
||||||
//if (hero && hero != g.hero)
|
|
||||||
// return false;
|
|
||||||
return town == g.town;
|
|
||||||
}
|
|
||||||
bool BuyArmy::fulfillsMe(TSubgoal goal)
|
bool BuyArmy::fulfillsMe(TSubgoal goal)
|
||||||
{
|
{
|
||||||
//if (hero && hero != goal->hero)
|
//if (hero && hero != goal->hero)
|
||||||
@ -294,16 +310,6 @@ TSubgoal Trade::whatToDoToAchieve()
|
|||||||
{
|
{
|
||||||
return iAmElementar();
|
return iAmElementar();
|
||||||
}
|
}
|
||||||
bool Trade::operator==(AbstractGoal & g)
|
|
||||||
{
|
|
||||||
if (g.goalType != goalType)
|
|
||||||
return false;
|
|
||||||
if (g.resID == resID)
|
|
||||||
if (g.value == value) //TODO: not sure if that logic is consitent
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TSubgoal AbstractGoal::whatToDoToAchieve()
|
//TSubgoal AbstractGoal::whatToDoToAchieve()
|
||||||
//{
|
//{
|
||||||
@ -465,6 +471,57 @@ TSubgoal Win::whatToDoToAchieve()
|
|||||||
return sptr(Goals::Invalid());
|
return sptr(Goals::Invalid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TSubgoal BuildBoat::whatToDoToAchieve()
|
||||||
|
{
|
||||||
|
if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
||||||
|
{
|
||||||
|
return fh->chooseSolution(ai->ah->howToVisitObj(shipyard->o));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(shipyard->shipyardStatus() != IShipyard::GOOD)
|
||||||
|
{
|
||||||
|
throw cannotFulfillGoalException("Shipyard is busy.");
|
||||||
|
}
|
||||||
|
|
||||||
|
TResources boatCost;
|
||||||
|
shipyard->getBoatCost(boatCost);
|
||||||
|
|
||||||
|
return ai->ah->whatToDo(boatCost, this->iAmElementar());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildBoat::accept(VCAI * ai)
|
||||||
|
{
|
||||||
|
TResources boatCost;
|
||||||
|
shipyard->getBoatCost(boatCost);
|
||||||
|
|
||||||
|
if(!cb->getResourceAmount().canAfford(boatCost))
|
||||||
|
{
|
||||||
|
throw cannotFulfillGoalException("Can not afford boat");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
||||||
|
{
|
||||||
|
throw cannotFulfillGoalException("Can not build boat in enemy shipyard");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(shipyard->shipyardStatus() != IShipyard::GOOD)
|
||||||
|
{
|
||||||
|
throw cannotFulfillGoalException("Shipyard is busy.");
|
||||||
|
}
|
||||||
|
|
||||||
|
cb->buildBoat(shipyard);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BuildBoat::name() const
|
||||||
|
{
|
||||||
|
return "BuildBoat";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BuildBoat::completeMessage() const
|
||||||
|
{
|
||||||
|
return "Boat have been built at " + shipyard->o->visitablePos().toString();
|
||||||
|
}
|
||||||
|
|
||||||
TSubgoal FindObj::whatToDoToAchieve()
|
TSubgoal FindObj::whatToDoToAchieve()
|
||||||
{
|
{
|
||||||
const CGObjectInstance * o = nullptr;
|
const CGObjectInstance * o = nullptr;
|
||||||
@ -575,13 +632,6 @@ Goals::VisitObj::VisitObj(int Objid) : CGoal(Goals::VISIT_OBJ)
|
|||||||
priority = 3;
|
priority = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Goals::VisitObj::operator==(AbstractGoal & g)
|
|
||||||
{
|
|
||||||
if (g.goalType != goalType)
|
|
||||||
return false;
|
|
||||||
return g.objid == objid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VisitObj::fulfillsMe(TSubgoal goal)
|
bool VisitObj::fulfillsMe(TSubgoal goal)
|
||||||
{
|
{
|
||||||
if(goal->goalType == Goals::VISIT_TILE)
|
if(goal->goalType == Goals::VISIT_TILE)
|
||||||
@ -622,13 +672,6 @@ TSubgoal VisitHero::whatToDoToAchieve()
|
|||||||
return sptr(Goals::Invalid());
|
return sptr(Goals::Invalid());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Goals::VisitHero::operator==(AbstractGoal & g)
|
|
||||||
{
|
|
||||||
if (g.goalType != goalType)
|
|
||||||
return false;
|
|
||||||
return g.hero == hero && g.objid == objid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VisitHero::fulfillsMe(TSubgoal goal)
|
bool VisitHero::fulfillsMe(TSubgoal goal)
|
||||||
{
|
{
|
||||||
//TODO: VisitObj shoudl not be used for heroes, but...
|
//TODO: VisitObj shoudl not be used for heroes, but...
|
||||||
@ -665,13 +708,6 @@ TSubgoal ClearWayTo::whatToDoToAchieve()
|
|||||||
return (fh->chooseSolution(getAllPossibleSubgoals()));
|
return (fh->chooseSolution(getAllPossibleSubgoals()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Goals::ClearWayTo::operator==(AbstractGoal & g)
|
|
||||||
{
|
|
||||||
if (g.goalType != goalType)
|
|
||||||
return false;
|
|
||||||
return g.goalType == goalType && g.tile == tile;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Goals::ClearWayTo::fulfillsMe(TSubgoal goal)
|
bool Goals::ClearWayTo::fulfillsMe(TSubgoal goal)
|
||||||
{
|
{
|
||||||
if (goal->goalType == Goals::VISIT_TILE)
|
if (goal->goalType == Goals::VISIT_TILE)
|
||||||
@ -876,14 +912,6 @@ TSubgoal RecruitHero::whatToDoToAchieve()
|
|||||||
return ai->ah->whatToDo(res, iAmElementar()); //either buy immediately, or collect res
|
return ai->ah->whatToDo(res, iAmElementar()); //either buy immediately, or collect res
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Goals::RecruitHero::operator==(AbstractGoal & g)
|
|
||||||
{
|
|
||||||
if (g.goalType != goalType)
|
|
||||||
return false;
|
|
||||||
//TODO: check town and hero
|
|
||||||
return true; //for now, recruiting any hero will do
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string VisitTile::completeMessage() const
|
std::string VisitTile::completeMessage() const
|
||||||
{
|
{
|
||||||
return "Hero " + hero.get()->name + " visited tile " + tile.toString();
|
return "Hero " + hero.get()->name + " visited tile " + tile.toString();
|
||||||
@ -909,13 +937,6 @@ TSubgoal VisitTile::whatToDoToAchieve()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Goals::VisitTile::operator==(AbstractGoal & g)
|
|
||||||
{
|
|
||||||
if (g.goalType != goalType)
|
|
||||||
return false;
|
|
||||||
return g.goalType == goalType && g.tile == tile;
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec VisitTile::getAllPossibleSubgoals()
|
TGoalVec VisitTile::getAllPossibleSubgoals()
|
||||||
{
|
{
|
||||||
assert(cb->isInTheMap(tile));
|
assert(cb->isInTheMap(tile));
|
||||||
@ -970,13 +991,6 @@ TSubgoal DigAtTile::whatToDoToAchieve()
|
|||||||
return sptr(Goals::VisitTile(tile));
|
return sptr(Goals::VisitTile(tile));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Goals::DigAtTile::operator==(AbstractGoal & g)
|
|
||||||
{
|
|
||||||
if (g.goalType != goalType)
|
|
||||||
return false;
|
|
||||||
return g.goalType == goalType && g.tile == tile;
|
|
||||||
}
|
|
||||||
|
|
||||||
TSubgoal BuildThis::whatToDoToAchieve()
|
TSubgoal BuildThis::whatToDoToAchieve()
|
||||||
{
|
{
|
||||||
auto b = BuildingID(bid);
|
auto b = BuildingID(bid);
|
||||||
@ -1195,17 +1209,6 @@ bool CollectRes::fulfillsMe(TSubgoal goal)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Goals::CollectRes::operator==(AbstractGoal & g)
|
|
||||||
{
|
|
||||||
if (g.goalType != goalType)
|
|
||||||
return false;
|
|
||||||
if (g.resID == resID)
|
|
||||||
if (g.value == value) //TODO: not sure if that logic is consitent
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
TSubgoal GatherTroops::whatToDoToAchieve()
|
TSubgoal GatherTroops::whatToDoToAchieve()
|
||||||
{
|
{
|
||||||
std::vector<const CGDwelling *> dwellings;
|
std::vector<const CGDwelling *> dwellings;
|
||||||
|
134
AI/VCAI/Goals.h
134
AI/VCAI/Goals.h
@ -59,7 +59,8 @@ enum EGoals
|
|||||||
CLEAR_WAY_TO,
|
CLEAR_WAY_TO,
|
||||||
DIG_AT_TILE,//elementar with hero on tile
|
DIG_AT_TILE,//elementar with hero on tile
|
||||||
BUY_ARMY, //at specific town
|
BUY_ARMY, //at specific town
|
||||||
TRADE //val resID at object objid
|
TRADE, //val resID at object objid
|
||||||
|
BUILD_BOAT
|
||||||
};
|
};
|
||||||
|
|
||||||
//method chaining + clone pattern
|
//method chaining + clone pattern
|
||||||
@ -74,6 +75,18 @@ enum {LOW_PR = -1};
|
|||||||
|
|
||||||
DLL_EXPORT TSubgoal sptr(const AbstractGoal & tmp);
|
DLL_EXPORT TSubgoal sptr(const AbstractGoal & tmp);
|
||||||
|
|
||||||
|
struct DLL_EXPORT EvaluationContext
|
||||||
|
{
|
||||||
|
uint64_t movementCost;
|
||||||
|
int manaCost;
|
||||||
|
uint64_t danger;
|
||||||
|
|
||||||
|
EvaluationContext()
|
||||||
|
:movementCost(0), danger(0), manaCost(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class DLL_EXPORT AbstractGoal
|
class DLL_EXPORT AbstractGoal
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -88,9 +101,11 @@ public:
|
|||||||
HeroPtr hero; VSETTER(HeroPtr, hero)
|
HeroPtr hero; VSETTER(HeroPtr, hero)
|
||||||
const CGTownInstance *town; VSETTER(CGTownInstance *, town)
|
const CGTownInstance *town; VSETTER(CGTownInstance *, town)
|
||||||
int bid; VSETTER(int, bid)
|
int bid; VSETTER(int, bid)
|
||||||
|
TSubgoal parent; VSETTER(TSubgoal, parent)
|
||||||
|
EvaluationContext evaluationContext; VSETTER(EvaluationContext, evaluationContext)
|
||||||
|
|
||||||
AbstractGoal(EGoals goal = INVALID)
|
AbstractGoal(EGoals goal = INVALID)
|
||||||
: goalType (goal)
|
: goalType (goal), evaluationContext()
|
||||||
{
|
{
|
||||||
priority = 0;
|
priority = 0;
|
||||||
isElementar = false;
|
isElementar = false;
|
||||||
@ -120,7 +135,7 @@ public:
|
|||||||
|
|
||||||
EGoals goalType;
|
EGoals goalType;
|
||||||
|
|
||||||
std::string name() const;
|
virtual std::string name() const;
|
||||||
virtual std::string completeMessage() const
|
virtual std::string completeMessage() const
|
||||||
{
|
{
|
||||||
return "This goal is unspecified!";
|
return "This goal is unspecified!";
|
||||||
@ -130,20 +145,24 @@ public:
|
|||||||
|
|
||||||
static TSubgoal goVisitOrLookFor(const CGObjectInstance * obj); //if obj is nullptr, then we'll explore
|
static TSubgoal goVisitOrLookFor(const CGObjectInstance * obj); //if obj is nullptr, then we'll explore
|
||||||
static TSubgoal lookForArtSmart(int aid); //checks non-standard ways of obtaining art (merchants, quests, etc.)
|
static TSubgoal lookForArtSmart(int aid); //checks non-standard ways of obtaining art (merchants, quests, etc.)
|
||||||
static TSubgoal tryRecruitHero();
|
|
||||||
|
|
||||||
///Visitor pattern
|
///Visitor pattern
|
||||||
//TODO: make accept work for std::shared_ptr... somehow
|
//TODO: make accept work for std::shared_ptr... somehow
|
||||||
virtual void accept(VCAI * ai); //unhandled goal will report standard error
|
virtual void accept(VCAI * ai); //unhandled goal will report standard error
|
||||||
virtual float accept(FuzzyHelper * f);
|
virtual float accept(FuzzyHelper * f);
|
||||||
|
|
||||||
virtual bool operator==(AbstractGoal & g);
|
virtual bool operator==(const AbstractGoal & g) const;
|
||||||
bool operator<(AbstractGoal & g); //final
|
bool operator<(AbstractGoal & g); //final
|
||||||
virtual bool fulfillsMe(Goals::TSubgoal goal) //TODO: multimethod instead of type check
|
virtual bool fulfillsMe(Goals::TSubgoal goal) //TODO: multimethod instead of type check
|
||||||
{
|
{
|
||||||
return false; //use this method to check if goal is fulfilled by another (not equal) goal, operator == is handled spearately
|
return false; //use this method to check if goal is fulfilled by another (not equal) goal, operator == is handled spearately
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator!=(const AbstractGoal & g) const
|
||||||
|
{
|
||||||
|
return !(*this == g);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Handler> void serialize(Handler & h, const int version)
|
template<typename Handler> void serialize(Handler & h, const int version)
|
||||||
{
|
{
|
||||||
h & goalType;
|
h & goalType;
|
||||||
@ -209,6 +228,16 @@ public:
|
|||||||
//h & goalType & isElementar & isAbstract & priority;
|
//h & goalType & isElementar & isAbstract & priority;
|
||||||
//h & value & resID & objid & aid & tile & hero & town & bid;
|
//h & value & resID & objid & aid & tile & hero & town & bid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool operator==(const AbstractGoal & g) const override
|
||||||
|
{
|
||||||
|
if(goalType != g.goalType)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (*this) == (dynamic_cast<const T &>(g));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool operator==(const T & other) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT Invalid : public CGoal<Invalid>
|
class DLL_EXPORT Invalid : public CGoal<Invalid>
|
||||||
@ -224,6 +253,11 @@ public:
|
|||||||
return TGoalVec();
|
return TGoalVec();
|
||||||
}
|
}
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
|
|
||||||
|
virtual bool operator==(const Invalid & other) const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT Win : public CGoal<Win>
|
class DLL_EXPORT Win : public CGoal<Win>
|
||||||
@ -239,6 +273,11 @@ public:
|
|||||||
return TGoalVec();
|
return TGoalVec();
|
||||||
}
|
}
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
|
|
||||||
|
virtual bool operator==(const Win & other) const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT NotLose : public CGoal<NotLose>
|
class DLL_EXPORT NotLose : public CGoal<NotLose>
|
||||||
@ -254,6 +293,11 @@ public:
|
|||||||
return TGoalVec();
|
return TGoalVec();
|
||||||
}
|
}
|
||||||
//TSubgoal whatToDoToAchieve() override;
|
//TSubgoal whatToDoToAchieve() override;
|
||||||
|
|
||||||
|
virtual bool operator==(const NotLose & other) const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT Conquer : public CGoal<Conquer>
|
class DLL_EXPORT Conquer : public CGoal<Conquer>
|
||||||
@ -266,6 +310,7 @@ public:
|
|||||||
}
|
}
|
||||||
TGoalVec getAllPossibleSubgoals() override;
|
TGoalVec getAllPossibleSubgoals() override;
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
|
virtual bool operator==(const Conquer & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT Build : public CGoal<Build>
|
class DLL_EXPORT Build : public CGoal<Build>
|
||||||
@ -279,6 +324,33 @@ public:
|
|||||||
TGoalVec getAllPossibleSubgoals() override;
|
TGoalVec getAllPossibleSubgoals() override;
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
bool fulfillsMe(TSubgoal goal) override;
|
bool fulfillsMe(TSubgoal goal) override;
|
||||||
|
|
||||||
|
virtual bool operator==(const Build & other) const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DLL_EXPORT BuildBoat : public CGoal<BuildBoat>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
const IShipyard * shipyard;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BuildBoat(const IShipyard * shipyard)
|
||||||
|
: CGoal(Goals::BUILD_BOAT), shipyard(shipyard)
|
||||||
|
{
|
||||||
|
priority = 0;
|
||||||
|
}
|
||||||
|
TGoalVec getAllPossibleSubgoals() override
|
||||||
|
{
|
||||||
|
return TGoalVec();
|
||||||
|
}
|
||||||
|
TSubgoal whatToDoToAchieve() override;
|
||||||
|
void accept(VCAI * ai) override;
|
||||||
|
std::string name() const override;
|
||||||
|
std::string completeMessage() const override;
|
||||||
|
virtual bool operator==(const BuildBoat & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT Explore : public CGoal<Explore>
|
class DLL_EXPORT Explore : public CGoal<Explore>
|
||||||
@ -299,6 +371,7 @@ public:
|
|||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
std::string completeMessage() const override;
|
std::string completeMessage() const override;
|
||||||
bool fulfillsMe(TSubgoal goal) override;
|
bool fulfillsMe(TSubgoal goal) override;
|
||||||
|
virtual bool operator==(const Explore & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT GatherArmy : public CGoal<GatherArmy>
|
class DLL_EXPORT GatherArmy : public CGoal<GatherArmy>
|
||||||
@ -317,6 +390,7 @@ public:
|
|||||||
TGoalVec getAllPossibleSubgoals() override;
|
TGoalVec getAllPossibleSubgoals() override;
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
std::string completeMessage() const override;
|
std::string completeMessage() const override;
|
||||||
|
virtual bool operator==(const GatherArmy & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT BuyArmy : public CGoal<BuyArmy>
|
class DLL_EXPORT BuyArmy : public CGoal<BuyArmy>
|
||||||
@ -333,11 +407,11 @@ public:
|
|||||||
value = val; //expressed in AI unit strength
|
value = val; //expressed in AI unit strength
|
||||||
priority = 3;//TODO: evaluate?
|
priority = 3;//TODO: evaluate?
|
||||||
}
|
}
|
||||||
bool operator==(AbstractGoal & g) override;
|
|
||||||
bool fulfillsMe(TSubgoal goal) override;
|
bool fulfillsMe(TSubgoal goal) override;
|
||||||
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
std::string completeMessage() const override;
|
std::string completeMessage() const override;
|
||||||
|
virtual bool operator==(const BuyArmy & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT BoostHero : public CGoal<BoostHero>
|
class DLL_EXPORT BoostHero : public CGoal<BoostHero>
|
||||||
@ -352,6 +426,7 @@ public:
|
|||||||
{
|
{
|
||||||
return TGoalVec();
|
return TGoalVec();
|
||||||
}
|
}
|
||||||
|
virtual bool operator==(const BoostHero & other) const override;
|
||||||
//TSubgoal whatToDoToAchieve() override {return sptr(Invalid());};
|
//TSubgoal whatToDoToAchieve() override {return sptr(Invalid());};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -363,12 +438,18 @@ public:
|
|||||||
{
|
{
|
||||||
priority = 1;
|
priority = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TGoalVec getAllPossibleSubgoals() override
|
TGoalVec getAllPossibleSubgoals() override
|
||||||
{
|
{
|
||||||
return TGoalVec();
|
return TGoalVec();
|
||||||
}
|
}
|
||||||
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
bool operator==(AbstractGoal & g) override;
|
|
||||||
|
virtual bool operator==(const RecruitHero & other) const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT BuildThis : public CGoal<BuildThis>
|
class DLL_EXPORT BuildThis : public CGoal<BuildThis>
|
||||||
@ -396,6 +477,7 @@ public:
|
|||||||
}
|
}
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
//bool fulfillsMe(TSubgoal goal) override;
|
//bool fulfillsMe(TSubgoal goal) override;
|
||||||
|
virtual bool operator==(const BuildThis & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT CollectRes : public CGoal<CollectRes>
|
class DLL_EXPORT CollectRes : public CGoal<CollectRes>
|
||||||
@ -416,7 +498,7 @@ public:
|
|||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
TSubgoal whatToDoToTrade();
|
TSubgoal whatToDoToTrade();
|
||||||
bool fulfillsMe(TSubgoal goal) override; //TODO: Trade
|
bool fulfillsMe(TSubgoal goal) override; //TODO: Trade
|
||||||
bool operator==(AbstractGoal & g) override;
|
virtual bool operator==(const CollectRes & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT Trade : public CGoal<Trade>
|
class DLL_EXPORT Trade : public CGoal<Trade>
|
||||||
@ -435,7 +517,7 @@ public:
|
|||||||
priority = 3; //trading is instant, but picking resources is free
|
priority = 3; //trading is instant, but picking resources is free
|
||||||
}
|
}
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
bool operator==(AbstractGoal & g) override;
|
virtual bool operator==(const Trade & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT GatherTroops : public CGoal<GatherTroops>
|
class DLL_EXPORT GatherTroops : public CGoal<GatherTroops>
|
||||||
@ -459,6 +541,7 @@ public:
|
|||||||
}
|
}
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
bool fulfillsMe(TSubgoal goal) override;
|
bool fulfillsMe(TSubgoal goal) override;
|
||||||
|
virtual bool operator==(const GatherTroops & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT VisitObj : public CGoal<VisitObj> //this goal was previously known as GetObj
|
class DLL_EXPORT VisitObj : public CGoal<VisitObj> //this goal was previously known as GetObj
|
||||||
@ -469,9 +552,9 @@ public:
|
|||||||
|
|
||||||
TGoalVec getAllPossibleSubgoals() override;
|
TGoalVec getAllPossibleSubgoals() override;
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
bool operator==(AbstractGoal & g) override;
|
|
||||||
bool fulfillsMe(TSubgoal goal) override;
|
bool fulfillsMe(TSubgoal goal) override;
|
||||||
std::string completeMessage() const override;
|
std::string completeMessage() const override;
|
||||||
|
virtual bool operator==(const VisitObj & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT FindObj : public CGoal<FindObj>
|
class DLL_EXPORT FindObj : public CGoal<FindObj>
|
||||||
@ -499,6 +582,7 @@ public:
|
|||||||
}
|
}
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
bool fulfillsMe(TSubgoal goal) override;
|
bool fulfillsMe(TSubgoal goal) override;
|
||||||
|
virtual bool operator==(const FindObj & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT VisitHero : public CGoal<VisitHero>
|
class DLL_EXPORT VisitHero : public CGoal<VisitHero>
|
||||||
@ -519,9 +603,9 @@ public:
|
|||||||
return TGoalVec();
|
return TGoalVec();
|
||||||
}
|
}
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
bool operator==(AbstractGoal & g) override;
|
|
||||||
bool fulfillsMe(TSubgoal goal) override;
|
bool fulfillsMe(TSubgoal goal) override;
|
||||||
std::string completeMessage() const override;
|
std::string completeMessage() const override;
|
||||||
|
virtual bool operator==(const VisitHero & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT GetArtOfType : public CGoal<GetArtOfType>
|
class DLL_EXPORT GetArtOfType : public CGoal<GetArtOfType>
|
||||||
@ -542,6 +626,7 @@ public:
|
|||||||
return TGoalVec();
|
return TGoalVec();
|
||||||
}
|
}
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
|
virtual bool operator==(const GetArtOfType & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT VisitTile : public CGoal<VisitTile>
|
class DLL_EXPORT VisitTile : public CGoal<VisitTile>
|
||||||
@ -558,8 +643,8 @@ public:
|
|||||||
}
|
}
|
||||||
TGoalVec getAllPossibleSubgoals() override;
|
TGoalVec getAllPossibleSubgoals() override;
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
bool operator==(AbstractGoal & g) override;
|
|
||||||
std::string completeMessage() const override;
|
std::string completeMessage() const override;
|
||||||
|
virtual bool operator==(const VisitTile & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT ClearWayTo : public CGoal<ClearWayTo>
|
class DLL_EXPORT ClearWayTo : public CGoal<ClearWayTo>
|
||||||
@ -584,8 +669,8 @@ public:
|
|||||||
}
|
}
|
||||||
TGoalVec getAllPossibleSubgoals() override;
|
TGoalVec getAllPossibleSubgoals() override;
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
bool operator==(AbstractGoal & g) override;
|
|
||||||
bool fulfillsMe(TSubgoal goal) override;
|
bool fulfillsMe(TSubgoal goal) override;
|
||||||
|
virtual bool operator==(const ClearWayTo & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT DigAtTile : public CGoal<DigAtTile>
|
class DLL_EXPORT DigAtTile : public CGoal<DigAtTile>
|
||||||
@ -607,28 +692,7 @@ public:
|
|||||||
return TGoalVec();
|
return TGoalVec();
|
||||||
}
|
}
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;
|
||||||
bool operator==(AbstractGoal & g) override;
|
virtual bool operator==(const DigAtTile & other) const override;
|
||||||
};
|
|
||||||
|
|
||||||
class DLL_EXPORT CIssueCommand : public CGoal<CIssueCommand>
|
|
||||||
{
|
|
||||||
std::function<bool()> command;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CIssueCommand()
|
|
||||||
: CGoal(ISSUE_COMMAND)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
CIssueCommand(std::function<bool()> _command)
|
|
||||||
: CGoal(ISSUE_COMMAND), command(_command)
|
|
||||||
{
|
|
||||||
priority = 1e10;
|
|
||||||
}
|
|
||||||
TGoalVec getAllPossibleSubgoals() override
|
|
||||||
{
|
|
||||||
return TGoalVec();
|
|
||||||
}
|
|
||||||
//TSubgoal whatToDoToAchieve() override {return sptr(Invalid());}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,15 +38,34 @@ bool AINodeStorage::isBattleNode(const CGPathNode * node) const
|
|||||||
return (getAINode(node)->chainMask & BATTLE_CHAIN) > 0;
|
return (getAINode(node)->chainMask & BATTLE_CHAIN) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AIPathNode * AINodeStorage::getNode(const int3 & coord, const EPathfindingLayer layer, int chainNumber)
|
boost::optional<AIPathNode *> AINodeStorage::getOrCreateNode(const int3 & pos, const EPathfindingLayer layer, int chainNumber)
|
||||||
{
|
{
|
||||||
return &nodes[coord.x][coord.y][coord.z][layer][chainNumber];
|
auto chains = nodes[pos.x][pos.y][pos.z][layer];
|
||||||
|
|
||||||
|
for(AIPathNode & node : chains)
|
||||||
|
{
|
||||||
|
if(node.chainMask == chainNumber)
|
||||||
|
{
|
||||||
|
return &node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.chainMask == 0)
|
||||||
|
{
|
||||||
|
node.chainMask = chainNumber;
|
||||||
|
|
||||||
|
return &node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return boost::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGPathNode * AINodeStorage::getInitialNode()
|
CGPathNode * AINodeStorage::getInitialNode()
|
||||||
{
|
{
|
||||||
auto hpos = hero->getPosition(false);
|
auto hpos = hero->getPosition(false);
|
||||||
auto initialNode = getNode(hpos, hero->boat ? EPathfindingLayer::SAIL : EPathfindingLayer::LAND, 0);
|
auto initialNode =
|
||||||
|
getOrCreateNode(hpos, hero->boat ? EPathfindingLayer::SAIL : EPathfindingLayer::LAND, NORMAL_CHAIN)
|
||||||
|
.get();
|
||||||
|
|
||||||
initialNode->turns = 0;
|
initialNode->turns = 0;
|
||||||
initialNode->moveRemains = hero->movement;
|
initialNode->moveRemains = hero->movement;
|
||||||
@ -61,7 +80,9 @@ void AINodeStorage::resetTile(const int3 & coord, EPathfindingLayer layer, CGPat
|
|||||||
{
|
{
|
||||||
AIPathNode & heroNode = nodes[coord.x][coord.y][coord.z][layer][i];
|
AIPathNode & heroNode = nodes[coord.x][coord.y][coord.z][layer][i];
|
||||||
|
|
||||||
heroNode.chainMask = i;
|
heroNode.chainMask = 0;
|
||||||
|
heroNode.danger = 0;
|
||||||
|
heroNode.specialAction.reset();
|
||||||
heroNode.update(coord, layer, accessibility);
|
heroNode.update(coord, layer, accessibility);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,12 +113,12 @@ std::vector<CGPathNode *> AINodeStorage::calculateNeighbours(
|
|||||||
{
|
{
|
||||||
for(EPathfindingLayer i = EPathfindingLayer::LAND; i <= EPathfindingLayer::AIR; i.advance(1))
|
for(EPathfindingLayer i = EPathfindingLayer::LAND; i <= EPathfindingLayer::AIR; i.advance(1))
|
||||||
{
|
{
|
||||||
auto nextNode = getNode(neighbour, i, srcNode->chainMask);
|
auto nextNode = getOrCreateNode(neighbour, i, srcNode->chainMask);
|
||||||
|
|
||||||
if(nextNode->accessible == CGPathNode::NOT_SET)
|
if(!nextNode || nextNode.get()->accessible == CGPathNode::NOT_SET)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
neighbours.push_back(nextNode);
|
neighbours.push_back(nextNode.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,9 +136,12 @@ std::vector<CGPathNode *> AINodeStorage::calculateTeleportations(
|
|||||||
|
|
||||||
for(auto & neighbour : accessibleExits)
|
for(auto & neighbour : accessibleExits)
|
||||||
{
|
{
|
||||||
auto node = getNode(neighbour, source.node->layer, srcNode->chainMask);
|
auto node = getOrCreateNode(neighbour, source.node->layer, srcNode->chainMask);
|
||||||
|
|
||||||
neighbours.push_back(node);
|
if(!node)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
neighbours.push_back(node.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
return neighbours;
|
return neighbours;
|
||||||
@ -183,8 +207,11 @@ std::vector<AIPath> AINodeStorage::getChainInfo(int3 pos) const
|
|||||||
pathNode.coord = current->coord;
|
pathNode.coord = current->coord;
|
||||||
|
|
||||||
path.nodes.push_back(pathNode);
|
path.nodes.push_back(pathNode);
|
||||||
|
path.specialAction = current->specialAction;
|
||||||
|
|
||||||
current = getAINode(current->theNodeBefore);
|
current = getAINode(current->theNodeBefore);
|
||||||
}
|
}
|
||||||
|
|
||||||
paths.push_back(path);
|
paths.push_back(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,17 +13,19 @@
|
|||||||
#include "../../../lib/CPathfinder.h"
|
#include "../../../lib/CPathfinder.h"
|
||||||
#include "../../../lib/mapObjects/CGHeroInstance.h"
|
#include "../../../lib/mapObjects/CGHeroInstance.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
#include "../Goals.h"
|
||||||
|
|
||||||
class IVirtualObject
|
class ISpecialAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void materialize();
|
virtual Goals::TSubgoal whatToDo(HeroPtr hero) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIPathNode : public CGPathNode
|
struct AIPathNode : public CGPathNode
|
||||||
{
|
{
|
||||||
uint32_t chainMask;
|
uint32_t chainMask;
|
||||||
uint64_t danger;
|
uint64_t danger;
|
||||||
|
std::shared_ptr<const ISpecialAction> specialAction;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIPathNodeInfo
|
struct AIPathNodeInfo
|
||||||
@ -38,6 +40,7 @@ struct AIPathNodeInfo
|
|||||||
struct AIPath
|
struct AIPath
|
||||||
{
|
{
|
||||||
std::vector<AIPathNodeInfo> nodes;
|
std::vector<AIPathNodeInfo> nodes;
|
||||||
|
std::shared_ptr<const ISpecialAction> specialAction;
|
||||||
|
|
||||||
AIPath();
|
AIPath();
|
||||||
|
|
||||||
@ -63,9 +66,13 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// more than 1 chain layer allows us to have more than 1 path to each tile so we can chose more optimal one.
|
/// more than 1 chain layer allows us to have more than 1 path to each tile so we can chose more optimal one.
|
||||||
static const int NUM_CHAINS = 2;
|
static const int NUM_CHAINS = 3;
|
||||||
static const int NORMAL_CHAIN = 0;
|
|
||||||
static const int BATTLE_CHAIN = 1;
|
// chain flags, can be combined
|
||||||
|
static const int NORMAL_CHAIN = 1;
|
||||||
|
static const int BATTLE_CHAIN = 2;
|
||||||
|
static const int CAST_CHAIN = 4;
|
||||||
|
static const int RESOURCE_CHAIN = 8;
|
||||||
|
|
||||||
AINodeStorage(const int3 & sizes);
|
AINodeStorage(const int3 & sizes);
|
||||||
~AINodeStorage();
|
~AINodeStorage();
|
||||||
@ -90,7 +97,7 @@ public:
|
|||||||
|
|
||||||
bool isBattleNode(const CGPathNode * node) const;
|
bool isBattleNode(const CGPathNode * node) const;
|
||||||
bool hasBetterChain(const PathNodeInfo & source, CDestinationNodeInfo & destination) const;
|
bool hasBetterChain(const PathNodeInfo & source, CDestinationNodeInfo & destination) const;
|
||||||
AIPathNode * getNode(const int3 & coord, const EPathfindingLayer layer, int chainNumber);
|
boost::optional<AIPathNode *> getOrCreateNode(const int3 & coord, const EPathfindingLayer layer, int chainNumber);
|
||||||
std::vector<AIPath> getChainInfo(int3 pos) const;
|
std::vector<AIPath> getChainInfo(int3 pos) const;
|
||||||
|
|
||||||
void setHero(HeroPtr heroPtr)
|
void setHero(HeroPtr heroPtr)
|
||||||
|
@ -16,8 +16,8 @@ std::vector<std::shared_ptr<AINodeStorage>> AIPathfinder::storagePool;
|
|||||||
std::map<HeroPtr, std::shared_ptr<AINodeStorage>> AIPathfinder::storageMap;
|
std::map<HeroPtr, std::shared_ptr<AINodeStorage>> AIPathfinder::storageMap;
|
||||||
boost::mutex AIPathfinder::storageMutex;
|
boost::mutex AIPathfinder::storageMutex;
|
||||||
|
|
||||||
AIPathfinder::AIPathfinder(CPlayerSpecificInfoCallback * cb)
|
AIPathfinder::AIPathfinder(CPlayerSpecificInfoCallback * cb, VCAI * ai)
|
||||||
:cb(cb)
|
:cb(cb), ai(ai)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ std::vector<AIPath> AIPathfinder::getPathInfo(HeroPtr hero, int3 tile)
|
|||||||
|
|
||||||
storageMap[hero] = nodeStorage;
|
storageMap[hero] = nodeStorage;
|
||||||
|
|
||||||
auto config = std::make_shared<AIPathfinderConfig>(cb, nodeStorage);
|
auto config = std::make_shared<AIPathfinderConfig>(cb, ai, nodeStorage);
|
||||||
|
|
||||||
nodeStorage->setHero(hero.get());
|
nodeStorage->setHero(hero.get());
|
||||||
cb->calculatePaths(config, hero.get());
|
cb->calculatePaths(config, hero.get());
|
||||||
|
@ -10,8 +10,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../AIUtility.h"
|
|
||||||
#include "AINodeStorage.h"
|
#include "AINodeStorage.h"
|
||||||
|
#include "../AIUtility.h"
|
||||||
|
#include "../VCAI.h"
|
||||||
|
|
||||||
class AIPathfinder
|
class AIPathfinder
|
||||||
{
|
{
|
||||||
@ -20,9 +21,10 @@ private:
|
|||||||
static std::map<HeroPtr, std::shared_ptr<AINodeStorage>> storageMap;
|
static std::map<HeroPtr, std::shared_ptr<AINodeStorage>> storageMap;
|
||||||
static boost::mutex storageMutex;
|
static boost::mutex storageMutex;
|
||||||
CPlayerSpecificInfoCallback * cb;
|
CPlayerSpecificInfoCallback * cb;
|
||||||
|
VCAI * ai;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AIPathfinder(CPlayerSpecificInfoCallback * cb);
|
AIPathfinder(CPlayerSpecificInfoCallback * cb, VCAI * ai);
|
||||||
std::vector<AIPath> getPathInfo(HeroPtr hero, int3 tile);
|
std::vector<AIPath> getPathInfo(HeroPtr hero, int3 tile);
|
||||||
void clear();
|
void clear();
|
||||||
};
|
};
|
||||||
|
@ -10,6 +10,119 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "AIPathfinderConfig.h"
|
#include "AIPathfinderConfig.h"
|
||||||
#include "../../../CCallback.h"
|
#include "../../../CCallback.h"
|
||||||
|
#include "../../../lib/mapping/CMap.h"
|
||||||
|
#include "../../../lib/mapObjects/MapObjects.h"
|
||||||
|
|
||||||
|
class BuildBoatAction : public ISpecialAction
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
const IShipyard * shipyard;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BuildBoatAction(const IShipyard * shipyard)
|
||||||
|
:shipyard(shipyard)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Goals::TSubgoal whatToDo(HeroPtr hero) const override
|
||||||
|
{
|
||||||
|
return sptr(Goals::BuildBoat(shipyard));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AILayerTransitionRule : public LayerTransitionRule
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CPlayerSpecificInfoCallback * cb;
|
||||||
|
VCAI * ai;
|
||||||
|
std::map<int3, std::shared_ptr<const BuildBoatAction>> virtualBoats;
|
||||||
|
std::shared_ptr<AINodeStorage> nodeStorage;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AILayerTransitionRule(CPlayerSpecificInfoCallback * cb, VCAI * ai, std::shared_ptr<AINodeStorage> nodeStorage)
|
||||||
|
:cb(cb), ai(ai), nodeStorage(nodeStorage)
|
||||||
|
{
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void process(
|
||||||
|
const PathNodeInfo & source,
|
||||||
|
CDestinationNodeInfo & destination,
|
||||||
|
const PathfinderConfig * pathfinderConfig,
|
||||||
|
CPathfinderHelper * pathfinderHelper) const override
|
||||||
|
{
|
||||||
|
LayerTransitionRule::process(source, destination, pathfinderConfig, pathfinderHelper);
|
||||||
|
|
||||||
|
if(!destination.blocked)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(source.node->layer == EPathfindingLayer::LAND && destination.node->layer == EPathfindingLayer::SAIL
|
||||||
|
&& vstd::contains(virtualBoats, destination.coord))
|
||||||
|
{
|
||||||
|
logAi->trace("Bypassing virtual boat at %s!", destination.coord.toString());
|
||||||
|
|
||||||
|
nodeStorage->updateAINode(destination.node, [&](AIPathNode * node)
|
||||||
|
{
|
||||||
|
std::shared_ptr<const BuildBoatAction> virtualBoat = virtualBoats.at(destination.coord);
|
||||||
|
|
||||||
|
auto boatNodeOptional = nodeStorage->getOrCreateNode(
|
||||||
|
node->coord,
|
||||||
|
node->layer,
|
||||||
|
node->chainMask | AINodeStorage::RESOURCE_CHAIN);
|
||||||
|
|
||||||
|
if(boatNodeOptional)
|
||||||
|
{
|
||||||
|
AIPathNode * boatNode = boatNodeOptional.get();
|
||||||
|
|
||||||
|
boatNode->specialAction = virtualBoat;
|
||||||
|
destination.blocked = false;
|
||||||
|
destination.action = CGPathNode::ENodeAction::EMBARK;
|
||||||
|
destination.node = boatNode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logAi->trace(
|
||||||
|
"Can not allocate boat node while moving %s -> %s",
|
||||||
|
source.coord.toString(),
|
||||||
|
destination.coord.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
std::vector<const IShipyard *> shipyards;
|
||||||
|
|
||||||
|
for(const CGTownInstance * t : cb->getTownsInfo())
|
||||||
|
{
|
||||||
|
if(t->hasBuilt(BuildingID::SHIPYARD))
|
||||||
|
shipyards.push_back(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const CGObjectInstance * obj : ai->visitableObjs)
|
||||||
|
{
|
||||||
|
if(obj->ID != Obj::TOWN) //towns were handled in the previous loop
|
||||||
|
{
|
||||||
|
if(const IShipyard * shipyard = IShipyard::castFrom(obj))
|
||||||
|
shipyards.push_back(shipyard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const IShipyard * shipyard : shipyards)
|
||||||
|
{
|
||||||
|
if(shipyard->shipyardStatus() == IShipyard::GOOD)
|
||||||
|
{
|
||||||
|
int3 boatLocation = shipyard->bestLocation();
|
||||||
|
virtualBoats[boatLocation] = std::make_shared<BuildBoatAction>(shipyard);
|
||||||
|
logAi->debug("Virtual boat added at %s", boatLocation.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class AIMovementAfterDestinationRule : public MovementAfterDestinationRule
|
class AIMovementAfterDestinationRule : public MovementAfterDestinationRule
|
||||||
{
|
{
|
||||||
@ -88,8 +201,25 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto destNode = nodeStorage->getAINode(destination.node);
|
const AIPathNode * destNode = nodeStorage->getAINode(destination.node);
|
||||||
auto battleNode = nodeStorage->getNode(destination.coord, destination.node->layer, destNode->chainMask | AINodeStorage::BATTLE_CHAIN);
|
auto battleNodeOptional = nodeStorage->getOrCreateNode(
|
||||||
|
destination.coord,
|
||||||
|
destination.node->layer,
|
||||||
|
destNode->chainMask | AINodeStorage::BATTLE_CHAIN);
|
||||||
|
|
||||||
|
if(!battleNodeOptional)
|
||||||
|
{
|
||||||
|
logAi->trace(
|
||||||
|
"Can not allocate battle node while moving %s -> %s",
|
||||||
|
source.coord.toString(),
|
||||||
|
destination.coord.toString());
|
||||||
|
|
||||||
|
destination.blocked = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AIPathNode * battleNode = battleNodeOptional.get();
|
||||||
|
|
||||||
if(battleNode->locked)
|
if(battleNode->locked)
|
||||||
{
|
{
|
||||||
@ -150,6 +280,13 @@ public:
|
|||||||
if(blocker == BlockingReason::NONE)
|
if(blocker == BlockingReason::NONE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if(blocker == BlockingReason::DESTINATION_BLOCKED
|
||||||
|
&& destination.action == CGPathNode::EMBARK
|
||||||
|
&& nodeStorage->getAINode(destination.node)->specialAction)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(blocker == BlockingReason::SOURCE_GUARDED && nodeStorage->isBattleNode(source.node))
|
if(blocker == BlockingReason::SOURCE_GUARDED && nodeStorage->isBattleNode(source.node))
|
||||||
{
|
{
|
||||||
auto srcGuardians = cb->getGuardingCreatures(source.coord);
|
auto srcGuardians = cb->getGuardingCreatures(source.coord);
|
||||||
@ -216,6 +353,8 @@ public:
|
|||||||
"Link src node %s to destination node %s while bypassing guard",
|
"Link src node %s to destination node %s while bypassing guard",
|
||||||
source.coord.toString(),
|
source.coord.toString(),
|
||||||
destination.coord.toString());
|
destination.coord.toString());
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,16 +367,27 @@ public:
|
|||||||
"Link src node %s to destination node %s while bypassing visitable obj",
|
"Link src node %s to destination node %s while bypassing visitable obj",
|
||||||
source.coord.toString(),
|
source.coord.toString(),
|
||||||
destination.coord.toString());
|
destination.coord.toString());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto aiSourceNode = nodeStorage->getAINode(source.node);
|
||||||
|
|
||||||
|
if(aiSourceNode->specialAction)
|
||||||
|
{
|
||||||
|
// there is some action on source tile which should be performed before we can bypass it
|
||||||
|
destination.node->theNodeBefore = source.node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::shared_ptr<IPathfindingRule>> makeRuleset(
|
std::vector<std::shared_ptr<IPathfindingRule>> makeRuleset(
|
||||||
CPlayerSpecificInfoCallback * cb,
|
CPlayerSpecificInfoCallback * cb,
|
||||||
|
VCAI * ai,
|
||||||
std::shared_ptr<AINodeStorage> nodeStorage)
|
std::shared_ptr<AINodeStorage> nodeStorage)
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<IPathfindingRule>> rules = {
|
std::vector<std::shared_ptr<IPathfindingRule>> rules = {
|
||||||
std::make_shared<LayerTransitionRule>(),
|
std::make_shared<AILayerTransitionRule>(cb, ai, nodeStorage),
|
||||||
std::make_shared<DestinationActionRule>(),
|
std::make_shared<DestinationActionRule>(),
|
||||||
std::make_shared<AIMovementToDestinationRule>(cb, nodeStorage),
|
std::make_shared<AIMovementToDestinationRule>(cb, nodeStorage),
|
||||||
std::make_shared<MovementCostRule>(),
|
std::make_shared<MovementCostRule>(),
|
||||||
@ -250,7 +400,8 @@ std::vector<std::shared_ptr<IPathfindingRule>> makeRuleset(
|
|||||||
|
|
||||||
AIPathfinderConfig::AIPathfinderConfig(
|
AIPathfinderConfig::AIPathfinderConfig(
|
||||||
CPlayerSpecificInfoCallback * cb,
|
CPlayerSpecificInfoCallback * cb,
|
||||||
|
VCAI * ai,
|
||||||
std::shared_ptr<AINodeStorage> nodeStorage)
|
std::shared_ptr<AINodeStorage> nodeStorage)
|
||||||
:PathfinderConfig(nodeStorage, makeRuleset(cb, nodeStorage))
|
:PathfinderConfig(nodeStorage, makeRuleset(cb, ai, nodeStorage))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "AINodeStorage.h"
|
#include "AINodeStorage.h"
|
||||||
|
#include "../VCAI.h"
|
||||||
|
|
||||||
class AIPathfinderConfig : public PathfinderConfig
|
class AIPathfinderConfig : public PathfinderConfig
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AIPathfinderConfig(CPlayerSpecificInfoCallback * cb, std::shared_ptr<AINodeStorage> nodeStorage);
|
AIPathfinderConfig(
|
||||||
|
CPlayerSpecificInfoCallback * cb,
|
||||||
|
VCAI * ai,
|
||||||
|
std::shared_ptr<AINodeStorage> nodeStorage);
|
||||||
};
|
};
|
@ -19,10 +19,10 @@ PathfindingManager::PathfindingManager(CPlayerSpecificInfoCallback * CB, VCAI *
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathfindingManager::setCB(CPlayerSpecificInfoCallback * CB)
|
void PathfindingManager::init(CPlayerSpecificInfoCallback * CB)
|
||||||
{
|
{
|
||||||
cb = CB;
|
cb = CB;
|
||||||
pathfinder.reset(new AIPathfinder(cb));
|
pathfinder.reset(new AIPathfinder(cb, ai));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathfindingManager::setAI(VCAI * AI)
|
void PathfindingManager::setAI(VCAI * AI)
|
||||||
@ -60,10 +60,17 @@ Goals::TGoalVec PathfindingManager::howToVisitObj(ObjectIdRef obj)
|
|||||||
|
|
||||||
Goals::TGoalVec PathfindingManager::howToVisitTile(HeroPtr hero, int3 tile, bool allowGatherArmy)
|
Goals::TGoalVec PathfindingManager::howToVisitTile(HeroPtr hero, int3 tile, bool allowGatherArmy)
|
||||||
{
|
{
|
||||||
return findPath(hero, tile, allowGatherArmy, [&](int3 firstTileToGet) -> Goals::TSubgoal
|
auto result = findPath(hero, tile, allowGatherArmy, [&](int3 firstTileToGet) -> Goals::TSubgoal
|
||||||
{
|
{
|
||||||
return sptr(Goals::VisitTile(firstTileToGet).sethero(hero).setisAbstract(true));
|
return sptr(Goals::VisitTile(firstTileToGet).sethero(hero).setisAbstract(true));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for(Goals::TSubgoal solution : result)
|
||||||
|
{
|
||||||
|
solution->setparent(sptr(Goals::VisitTile(tile).sethero(hero).setevaluationContext(solution->evaluationContext)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TGoalVec PathfindingManager::howToVisitObj(HeroPtr hero, ObjectIdRef obj, bool allowGatherArmy)
|
Goals::TGoalVec PathfindingManager::howToVisitObj(HeroPtr hero, ObjectIdRef obj, bool allowGatherArmy)
|
||||||
@ -75,13 +82,20 @@ Goals::TGoalVec PathfindingManager::howToVisitObj(HeroPtr hero, ObjectIdRef obj,
|
|||||||
|
|
||||||
int3 dest = obj->visitablePos();
|
int3 dest = obj->visitablePos();
|
||||||
|
|
||||||
return findPath(hero, dest, allowGatherArmy, [&](int3 firstTileToGet) -> Goals::TSubgoal
|
auto result = findPath(hero, dest, allowGatherArmy, [&](int3 firstTileToGet) -> Goals::TSubgoal
|
||||||
{
|
{
|
||||||
if(obj->ID.num == Obj::HERO && obj->getOwner() == hero->getOwner())
|
if(obj->ID.num == Obj::HERO && obj->getOwner() == hero->getOwner())
|
||||||
return sptr(Goals::VisitHero(obj->id.getNum()).sethero(hero).setisAbstract(true));
|
return sptr(Goals::VisitHero(obj->id.getNum()).sethero(hero).setisAbstract(true));
|
||||||
else
|
else
|
||||||
return sptr(Goals::VisitObj(obj->id.getNum()).sethero(hero).setisAbstract(true));
|
return sptr(Goals::VisitObj(obj->id.getNum()).sethero(hero).setisAbstract(true));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for(Goals::TSubgoal solution : result)
|
||||||
|
{
|
||||||
|
solution->setparent(sptr(Goals::VisitObj(obj->id.getNum()).sethero(hero).setevaluationContext(solution->evaluationContext)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<AIPath> PathfindingManager::getPathsToTile(HeroPtr hero, int3 tile)
|
std::vector<AIPath> PathfindingManager::getPathsToTile(HeroPtr hero, int3 tile)
|
||||||
@ -117,9 +131,24 @@ Goals::TGoalVec PathfindingManager::findPath(
|
|||||||
{
|
{
|
||||||
logAi->trace("It's safe for %s to visit tile %s with danger %s", hero->name, dest.toString(), std::to_string(danger));
|
logAi->trace("It's safe for %s to visit tile %s with danger %s", hero->name, dest.toString(), std::to_string(danger));
|
||||||
|
|
||||||
auto solution = dest == firstTileToGet
|
Goals::TSubgoal solution;
|
||||||
? doVisitTile(firstTileToGet)
|
|
||||||
: clearWayTo(hero, firstTileToGet);
|
if(path.specialAction)
|
||||||
|
{
|
||||||
|
solution = path.specialAction->whatToDo(hero);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solution = dest == firstTileToGet
|
||||||
|
? doVisitTile(firstTileToGet)
|
||||||
|
: clearWayTo(hero, firstTileToGet);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(solution->evaluationContext.danger < danger)
|
||||||
|
solution->evaluationContext.danger = danger;
|
||||||
|
|
||||||
|
solution->evaluationContext.movementCost += path.movementCost();
|
||||||
|
|
||||||
result.push_back(solution);
|
result.push_back(solution);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -17,7 +17,7 @@ class IPathfindingManager
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IPathfindingManager() = default;
|
virtual ~IPathfindingManager() = default;
|
||||||
virtual void setCB(CPlayerSpecificInfoCallback * CB) = 0;
|
virtual void init(CPlayerSpecificInfoCallback * CB) = 0;
|
||||||
virtual void setAI(VCAI * AI) = 0;
|
virtual void setAI(VCAI * AI) = 0;
|
||||||
|
|
||||||
virtual void resetPaths() = 0;
|
virtual void resetPaths() = 0;
|
||||||
@ -49,7 +49,7 @@ public:
|
|||||||
void resetPaths() override;
|
void resetPaths() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setCB(CPlayerSpecificInfoCallback * CB) override;
|
void init(CPlayerSpecificInfoCallback * CB) override;
|
||||||
void setAI(VCAI * AI) override;
|
void setAI(VCAI * AI) override;
|
||||||
|
|
||||||
Goals::TGoalVec findPath(
|
Goals::TGoalVec findPath(
|
||||||
|
@ -30,7 +30,7 @@ ResourceManager::ResourceManager(CPlayerSpecificInfoCallback * CB, VCAI * AI)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceManager::setCB(CPlayerSpecificInfoCallback * CB)
|
void ResourceManager::init(CPlayerSpecificInfoCallback * CB)
|
||||||
{
|
{
|
||||||
cb = CB;
|
cb = CB;
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class IResourceManager //: public: IAbstractManager
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IResourceManager() = default;
|
virtual ~IResourceManager() = default;
|
||||||
virtual void setCB(CPlayerSpecificInfoCallback * CB) = 0;
|
virtual void init(CPlayerSpecificInfoCallback * CB) = 0;
|
||||||
virtual void setAI(VCAI * AI) = 0;
|
virtual void setAI(VCAI * AI) = 0;
|
||||||
|
|
||||||
virtual TResources reservedResources() const = 0;
|
virtual TResources reservedResources() const = 0;
|
||||||
@ -94,7 +94,7 @@ protected: //not-const actions only for AI
|
|||||||
virtual TResources estimateIncome() const;
|
virtual TResources estimateIncome() const;
|
||||||
virtual Goals::TSubgoal collectResourcesForOurGoal(ResourceObjective &o) const;
|
virtual Goals::TSubgoal collectResourcesForOurGoal(ResourceObjective &o) const;
|
||||||
|
|
||||||
void setCB(CPlayerSpecificInfoCallback * CB) override;
|
void init(CPlayerSpecificInfoCallback * CB) override;
|
||||||
void setAI(VCAI * AI) override;
|
void setAI(VCAI * AI) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -613,7 +613,7 @@ void VCAI::init(std::shared_ptr<CCallback> CB)
|
|||||||
myCb = CB;
|
myCb = CB;
|
||||||
cbc = CB;
|
cbc = CB;
|
||||||
|
|
||||||
ah->setCB(CB.get());
|
ah->init(CB.get());
|
||||||
|
|
||||||
NET_EVENT_HANDLER; //sets ah->rm->cb
|
NET_EVENT_HANDLER; //sets ah->rm->cb
|
||||||
playerID = *myCb->getMyColor();
|
playerID = *myCb->getMyColor();
|
||||||
@ -907,6 +907,14 @@ void VCAI::mainLoop()
|
|||||||
completeGoal(e.goal); //put in goalsToRemove
|
completeGoal(e.goal); //put in goalsToRemove
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
catch(cannotFulfillGoalException & e)
|
||||||
|
{
|
||||||
|
//it is impossible to continue some goals (like exploration, for example)
|
||||||
|
//complete abstract goal for now, but maybe main goal finds another path
|
||||||
|
goalsToRemove.push_back(basicGoal);
|
||||||
|
logAi->debug("Goal %s decomposition failed: %s", goalToDecompose->name(), e.what());
|
||||||
|
break;
|
||||||
|
}
|
||||||
catch (std::exception & e) //decomposition failed, which means we can't decompose entire tree
|
catch (std::exception & e) //decomposition failed, which means we can't decompose entire tree
|
||||||
{
|
{
|
||||||
goalsToRemove.push_back(basicGoal);
|
goalsToRemove.push_back(basicGoal);
|
||||||
@ -2397,6 +2405,7 @@ Goals::TSubgoal VCAI::decomposeGoal(Goals::TSubgoal ultimateGoal)
|
|||||||
while (maxGoals)
|
while (maxGoals)
|
||||||
{
|
{
|
||||||
boost::this_thread::interruption_point();
|
boost::this_thread::interruption_point();
|
||||||
|
|
||||||
goal = goal->whatToDoToAchieve(); //may throw if decomposition fails
|
goal = goal->whatToDoToAchieve(); //may throw if decomposition fails
|
||||||
--maxGoals;
|
--maxGoals;
|
||||||
if (goal == ultimateGoal) //compare objects by value
|
if (goal == ultimateGoal) //compare objects by value
|
||||||
|
@ -696,6 +696,7 @@ void DestinationActionRule::process(
|
|||||||
{
|
{
|
||||||
if(destination.action != CGPathNode::ENodeAction::UNKNOWN)
|
if(destination.action != CGPathNode::ENodeAction::UNKNOWN)
|
||||||
{
|
{
|
||||||
|
logAi->trace("Accepted precalculated action at %s", destination.coord.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user