mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-26 03:52:01 +02:00
Nullkiller: initial decomposition
This commit is contained in:
parent
223a52b3d1
commit
8f8c5ca255
@ -36,9 +36,9 @@ extern const int GOLD_RESERVE;
|
|||||||
|
|
||||||
enum HeroRole
|
enum HeroRole
|
||||||
{
|
{
|
||||||
MAIN,
|
SCOUT,
|
||||||
|
|
||||||
SCOUT
|
MAIN
|
||||||
};
|
};
|
||||||
|
|
||||||
//provisional class for AI to store a reference to an owned hero object
|
//provisional class for AI to store a reference to an owned hero object
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "../AIhelper.h"
|
#include "../AIhelper.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
#include "../Goals/BuyArmy.h"
|
#include "../Goals/BuyArmy.h"
|
||||||
#include "../Goals/VisitTile.h"
|
|
||||||
#include "lib/mapping/CMap.h" //for victory conditions
|
#include "lib/mapping/CMap.h" //for victory conditions
|
||||||
#include "lib/CPathfinder.h"
|
#include "lib/CPathfinder.h"
|
||||||
#include "../Engine/Nullkiller.h"
|
#include "../Engine/Nullkiller.h"
|
||||||
|
@ -19,6 +19,7 @@ namespace Goals
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BuildingBehavior()
|
BuildingBehavior()
|
||||||
|
:CGoal(Goals::BUILD)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "../AIhelper.h"
|
#include "../AIhelper.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
#include "../Goals/BuyArmy.h"
|
#include "../Goals/BuyArmy.h"
|
||||||
#include "../Goals/VisitTile.h"
|
|
||||||
#include "../Engine/Nullkiller.h"
|
#include "../Engine/Nullkiller.h"
|
||||||
#include "lib/mapping/CMap.h" //for victory conditions
|
#include "lib/mapping/CMap.h" //for victory conditions
|
||||||
#include "lib/CPathfinder.h"
|
#include "lib/CPathfinder.h"
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "../VCAI.h"
|
#include "../VCAI.h"
|
||||||
#include "../Engine/Nullkiller.h"
|
#include "../Engine/Nullkiller.h"
|
||||||
#include "../AIhelper.h"
|
#include "../AIhelper.h"
|
||||||
|
#include "../Goals/Composition.h"
|
||||||
#include "../Goals/ExecuteHeroChain.h"
|
#include "../Goals/ExecuteHeroChain.h"
|
||||||
#include "CaptureObjectsBehavior.h"
|
#include "CaptureObjectsBehavior.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
@ -23,11 +24,32 @@ extern FuzzyHelper * fh;
|
|||||||
|
|
||||||
using namespace Goals;
|
using namespace Goals;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool vectorEquals(const std::vector<T> & v1, const std::vector<T> & v2)
|
||||||
|
{
|
||||||
|
return vstd::contains_if(v1, [&](T o) -> bool
|
||||||
|
{
|
||||||
|
return vstd::contains(v2, o);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
std::string CaptureObjectsBehavior::toString() const
|
std::string CaptureObjectsBehavior::toString() const
|
||||||
{
|
{
|
||||||
return "Capture objects";
|
return "Capture objects";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CaptureObjectsBehavior::operator==(const CaptureObjectsBehavior & other) const
|
||||||
|
{
|
||||||
|
if(specificObjects != other.specificObjects)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(specificObjects)
|
||||||
|
return vectorEquals(objectsToCapture, other.objectsToCapture);
|
||||||
|
|
||||||
|
return vectorEquals(objectTypes, other.objectTypes)
|
||||||
|
&& vectorEquals(objectSubTypes, other.objectSubTypes);
|
||||||
|
}
|
||||||
|
|
||||||
Goals::TGoalVec CaptureObjectsBehavior::decompose() const
|
Goals::TGoalVec CaptureObjectsBehavior::decompose() const
|
||||||
{
|
{
|
||||||
Goals::TGoalVec tasks;
|
Goals::TGoalVec tasks;
|
||||||
@ -65,15 +87,6 @@ Goals::TGoalVec CaptureObjectsBehavior::decompose() const
|
|||||||
logAi->trace("Path found %s", path.toString());
|
logAi->trace("Path found %s", path.toString());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(path.getFirstBlockedAction())
|
|
||||||
{
|
|
||||||
#if AI_TRACE_LEVEL >= 2
|
|
||||||
// TODO: decomposition?
|
|
||||||
logAi->trace("Ignore path. Action is blocked.");
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
|
if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
|
||||||
{
|
{
|
||||||
#if AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
@ -91,9 +104,26 @@ Goals::TGoalVec CaptureObjectsBehavior::decompose() const
|
|||||||
if(ai->ah->getHeroRole(hero) == HeroRole::SCOUT && danger == 0 && path.exchangeCount > 1)
|
if(ai->ah->getHeroRole(hero) == HeroRole::SCOUT && danger == 0 && path.exchangeCount > 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(path.specialAction && !path.specialAction->canAct(path.targetHero))
|
auto firstBlockedAction = path.getFirstBlockedAction();
|
||||||
|
if(firstBlockedAction)
|
||||||
{
|
{
|
||||||
auto subGoal = path.specialAction->whatToDo(path.targetHero);
|
auto subGoal = firstBlockedAction->decompose(path.targetHero);
|
||||||
|
|
||||||
|
#if AI_TRACE_LEVEL >= 2
|
||||||
|
logAi->trace("Decomposing special action %s returns %s", firstBlockedAction->toString(), subGoal->toString());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(!subGoal->invalid())
|
||||||
|
{
|
||||||
|
Composition composition;
|
||||||
|
|
||||||
|
composition.addNext(ExecuteHeroChain(path, objToVisit));
|
||||||
|
composition.addNext(subGoal);
|
||||||
|
|
||||||
|
tasks.push_back(sptr(composition));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);
|
auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);
|
||||||
@ -115,7 +145,7 @@ Goals::TGoalVec CaptureObjectsBehavior::decompose() const
|
|||||||
|
|
||||||
waysToVisitObj.push_back(newWay);
|
waysToVisitObj.push_back(newWay);
|
||||||
|
|
||||||
if(!closestWay || closestWay->evaluationContext.movementCost > newWay->evaluationContext.movementCost)
|
if(!closestWay || closestWay->getPath().movementCost() > newWay->getPath().movementCost())
|
||||||
closestWay = newWay;
|
closestWay = newWay;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,8 +158,8 @@ Goals::TGoalVec CaptureObjectsBehavior::decompose() const
|
|||||||
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
way->evaluationContext.closestWayRatio
|
way->closestWayRatio
|
||||||
= closestWay->evaluationContext.movementCost / way->evaluationContext.movementCost;
|
= closestWay->getPath().movementCost() / way->getPath().movementCost();
|
||||||
|
|
||||||
tasks.push_back(sptr(*way));
|
tasks.push_back(sptr(*way));
|
||||||
}
|
}
|
||||||
|
@ -24,18 +24,21 @@ namespace Goals
|
|||||||
bool specificObjects;
|
bool specificObjects;
|
||||||
public:
|
public:
|
||||||
CaptureObjectsBehavior()
|
CaptureObjectsBehavior()
|
||||||
|
:CGoal(CAPTURE_OBJECTS)
|
||||||
{
|
{
|
||||||
objectTypes = std::vector<int>();
|
objectTypes = std::vector<int>();
|
||||||
specificObjects = false;
|
specificObjects = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CaptureObjectsBehavior(std::vector<const CGObjectInstance *> objectsToCapture)
|
CaptureObjectsBehavior(std::vector<const CGObjectInstance *> objectsToCapture)
|
||||||
|
:CGoal(CAPTURE_OBJECTS)
|
||||||
{
|
{
|
||||||
this->objectsToCapture = objectsToCapture;
|
this->objectsToCapture = objectsToCapture;
|
||||||
specificObjects = true;
|
specificObjects = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CaptureObjectsBehavior(const CGObjectInstance * objectToCapture)
|
CaptureObjectsBehavior(const CGObjectInstance * objectToCapture)
|
||||||
|
:CGoal(CAPTURE_OBJECTS)
|
||||||
{
|
{
|
||||||
objectsToCapture = std::vector<const CGObjectInstance *>();
|
objectsToCapture = std::vector<const CGObjectInstance *>();
|
||||||
objectsToCapture.push_back(objectToCapture);
|
objectsToCapture.push_back(objectToCapture);
|
||||||
@ -59,10 +62,7 @@ namespace Goals
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator==(const CaptureObjectsBehavior & other) const override
|
virtual bool operator==(const CaptureObjectsBehavior & other) const override;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool shouldVisitObject(ObjectIdRef obj) const;
|
bool shouldVisitObject(ObjectIdRef obj) const;
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lib/VCMI_Lib.h"
|
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
#include "../../../lib/VCMI_Lib.h"
|
#include "../../../lib/VCMI_Lib.h"
|
||||||
#include "../../../CCallback.h"
|
#include "../../../CCallback.h"
|
||||||
@ -21,6 +20,7 @@ namespace Goals
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CompleteQuestBehavior()
|
CompleteQuestBehavior()
|
||||||
|
:CGoal(COMPLETE_QUEST)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ namespace Goals
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DefenceBehavior()
|
DefenceBehavior()
|
||||||
|
:CGoal(DEFENCE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
|
|||||||
{
|
{
|
||||||
auto newWay = std::make_shared<ExecuteHeroChain>(path, hero);
|
auto newWay = std::make_shared<ExecuteHeroChain>(path, hero);
|
||||||
|
|
||||||
newWay->evaluationContext.strategicalValue = armyValue;
|
newWay->strategicalValue = armyValue;
|
||||||
waysToVisitObj.push_back(newWay);
|
waysToVisitObj.push_back(newWay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,7 +148,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
|
|||||||
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
way->evaluationContext.closestWayRatio = 1;
|
way->closestWayRatio = 1;
|
||||||
|
|
||||||
tasks.push_back(sptr(*way));
|
tasks.push_back(sptr(*way));
|
||||||
}
|
}
|
||||||
@ -228,8 +228,8 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
|
|||||||
{
|
{
|
||||||
auto newWay = std::make_shared<ExecuteHeroChain>(path, upgrader);
|
auto newWay = std::make_shared<ExecuteHeroChain>(path, upgrader);
|
||||||
|
|
||||||
newWay->evaluationContext.strategicalValue = armyValue;
|
newWay->strategicalValue = armyValue;
|
||||||
newWay->evaluationContext.goldCost = upgrade.upgradeCost[Res::GOLD];
|
newWay->goldCost = upgrade.upgradeCost[Res::GOLD];
|
||||||
|
|
||||||
waysToVisitObj.push_back(newWay);
|
waysToVisitObj.push_back(newWay);
|
||||||
}
|
}
|
||||||
@ -243,7 +243,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
|
|||||||
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
way->evaluationContext.closestWayRatio = 1;
|
way->closestWayRatio = 1;
|
||||||
|
|
||||||
tasks.push_back(sptr(*way));
|
tasks.push_back(sptr(*way));
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ namespace Goals
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GatherArmyBehavior()
|
GatherArmyBehavior()
|
||||||
|
:CGoal(Goals::GATHER_ARMY)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ namespace Goals
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RecruitHeroBehavior()
|
RecruitHeroBehavior()
|
||||||
|
:CGoal(RECRUIT_HERO_BEHAVIOR)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ namespace Goals
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StartupBehavior()
|
StartupBehavior()
|
||||||
|
:CGoal(STARTUP)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ set(VCAI_SRCS
|
|||||||
Pathfinding/AINodeStorage.cpp
|
Pathfinding/AINodeStorage.cpp
|
||||||
Pathfinding/PathfindingManager.cpp
|
Pathfinding/PathfindingManager.cpp
|
||||||
Pathfinding/Actors.cpp
|
Pathfinding/Actors.cpp
|
||||||
|
Pathfinding/Actions/SpecialAction.cpp
|
||||||
Pathfinding/Actions/BattleAction.cpp
|
Pathfinding/Actions/BattleAction.cpp
|
||||||
Pathfinding/Actions/BoatActions.cpp
|
Pathfinding/Actions/BoatActions.cpp
|
||||||
Pathfinding/Actions/TownPortalAction.cpp
|
Pathfinding/Actions/TownPortalAction.cpp
|
||||||
@ -21,6 +22,7 @@ set(VCAI_SRCS
|
|||||||
FuzzyEngines.cpp
|
FuzzyEngines.cpp
|
||||||
FuzzyHelper.cpp
|
FuzzyHelper.cpp
|
||||||
Goals/AbstractGoal.cpp
|
Goals/AbstractGoal.cpp
|
||||||
|
Goals/Composition.cpp
|
||||||
Goals/BuildBoat.cpp
|
Goals/BuildBoat.cpp
|
||||||
Goals/BuildThis.cpp
|
Goals/BuildThis.cpp
|
||||||
Goals/DismissHero.cpp
|
Goals/DismissHero.cpp
|
||||||
@ -32,7 +34,6 @@ set(VCAI_SRCS
|
|||||||
Goals/RecruitHero.cpp
|
Goals/RecruitHero.cpp
|
||||||
Goals/DigAtTile.cpp
|
Goals/DigAtTile.cpp
|
||||||
Goals/GetArtOfType.cpp
|
Goals/GetArtOfType.cpp
|
||||||
Goals/FindObj.cpp
|
|
||||||
Goals/ExecuteHeroChain.cpp
|
Goals/ExecuteHeroChain.cpp
|
||||||
Goals/ExchangeSwapTownHeroes.cpp
|
Goals/ExchangeSwapTownHeroes.cpp
|
||||||
Engine/Nullkiller.cpp
|
Engine/Nullkiller.cpp
|
||||||
@ -59,7 +60,7 @@ set(VCAI_HEADERS
|
|||||||
Pathfinding/AINodeStorage.h
|
Pathfinding/AINodeStorage.h
|
||||||
Pathfinding/PathfindingManager.h
|
Pathfinding/PathfindingManager.h
|
||||||
Pathfinding/Actors.h
|
Pathfinding/Actors.h
|
||||||
Pathfinding/Actions/ISpecialAction.h
|
Pathfinding/Actions/SpecialAction.h
|
||||||
Pathfinding/Actions/BattleAction.h
|
Pathfinding/Actions/BattleAction.h
|
||||||
Pathfinding/Actions/BoatActions.h
|
Pathfinding/Actions/BoatActions.h
|
||||||
Pathfinding/Actions/TownPortalAction.h
|
Pathfinding/Actions/TownPortalAction.h
|
||||||
@ -76,6 +77,7 @@ set(VCAI_HEADERS
|
|||||||
FuzzyHelper.h
|
FuzzyHelper.h
|
||||||
Goals/AbstractGoal.h
|
Goals/AbstractGoal.h
|
||||||
Goals/CGoal.h
|
Goals/CGoal.h
|
||||||
|
Goals/Composition.h
|
||||||
Goals/Invalid.h
|
Goals/Invalid.h
|
||||||
Goals/BuildBoat.h
|
Goals/BuildBoat.h
|
||||||
Goals/BuildThis.h
|
Goals/BuildThis.h
|
||||||
@ -88,7 +90,6 @@ set(VCAI_HEADERS
|
|||||||
Goals/RecruitHero.h
|
Goals/RecruitHero.h
|
||||||
Goals/DigAtTile.h
|
Goals/DigAtTile.h
|
||||||
Goals/GetArtOfType.h
|
Goals/GetArtOfType.h
|
||||||
Goals/FindObj.h
|
|
||||||
Goals/ExecuteHeroChain.h
|
Goals/ExecuteHeroChain.h
|
||||||
Goals/ExchangeSwapTownHeroes.h
|
Goals/ExchangeSwapTownHeroes.h
|
||||||
Goals/Goals.h
|
Goals/Goals.h
|
||||||
|
@ -51,29 +51,33 @@ Goals::TTask Nullkiller::choseBestTask(Goals::TSubgoal behavior) const
|
|||||||
|
|
||||||
goals[0] = {behavior};
|
goals[0] = {behavior};
|
||||||
|
|
||||||
if(tasks.empty())
|
|
||||||
{
|
|
||||||
logAi->debug("Behavior %s found no tasks", behavior->toString());
|
|
||||||
|
|
||||||
return Goals::taskptr(Goals::Invalid());
|
|
||||||
}
|
|
||||||
|
|
||||||
logAi->trace("Evaluating priorities, tasks count %d", tasks.size());
|
|
||||||
|
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
while(goals[0].size())
|
while(goals[0].size())
|
||||||
{
|
{
|
||||||
TSubgoal current = goals[depth].back();
|
TSubgoal current = goals[depth].back();
|
||||||
|
|
||||||
|
#if AI_TRACE_LEVEL >= 1
|
||||||
|
logAi->trace("Decomposing %s, level: %d", current->toString(), depth);
|
||||||
|
#endif
|
||||||
|
|
||||||
TGoalVec subgoals = current->decompose();
|
TGoalVec subgoals = current->decompose();
|
||||||
|
|
||||||
|
#if AI_TRACE_LEVEL >= 1
|
||||||
|
logAi->trace("Found %d goals", subgoals.size());
|
||||||
|
#endif
|
||||||
|
|
||||||
goals[depth + 1].clear();
|
goals[depth + 1].clear();
|
||||||
|
|
||||||
for(auto subgoal : subgoals)
|
for(auto subgoal : subgoals)
|
||||||
{
|
{
|
||||||
if(subgoal->isElementar)
|
if(subgoal->isElementar())
|
||||||
{
|
{
|
||||||
auto task = taskptr(*subgoal);
|
auto task = taskptr(*subgoal);
|
||||||
|
|
||||||
|
#if AI_TRACE_LEVEL >= 1
|
||||||
|
logAi->trace("Found task %s", task->toString());
|
||||||
|
#endif
|
||||||
|
|
||||||
if(task->priority <= 0)
|
if(task->priority <= 0)
|
||||||
task->priority = priorityEvaluator->evaluate(subgoal);
|
task->priority = priorityEvaluator->evaluate(subgoal);
|
||||||
|
|
||||||
@ -81,6 +85,9 @@ Goals::TTask Nullkiller::choseBestTask(Goals::TSubgoal behavior) const
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#if AI_TRACE_LEVEL >= 1
|
||||||
|
logAi->trace("Found abstract goal %s", subgoal->toString());
|
||||||
|
#endif
|
||||||
goals[depth + 1].push_back(subgoal);
|
goals[depth + 1].push_back(subgoal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,13 +98,23 @@ Goals::TTask Nullkiller::choseBestTask(Goals::TSubgoal behavior) const
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
goals[depth].pop_back();
|
||||||
|
|
||||||
while(depth > 0 && goals[depth].empty())
|
while(depth > 0 && goals[depth].empty())
|
||||||
{
|
{
|
||||||
depth--;
|
depth--;
|
||||||
|
goals[depth].pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(tasks.empty())
|
||||||
|
{
|
||||||
|
logAi->debug("Behavior %s found no tasks", behavior->toString());
|
||||||
|
|
||||||
|
return Goals::taskptr(Goals::Invalid());
|
||||||
|
}
|
||||||
|
|
||||||
auto task = choseBestTask(tasks);
|
auto task = choseBestTask(tasks);
|
||||||
|
|
||||||
logAi->debug("Behavior %s returns %s, priority %f", behavior->toString(), task->toString(), task->priority);
|
logAi->debug("Behavior %s returns %s, priority %f", behavior->toString(), task->toString(), task->priority);
|
||||||
|
@ -36,6 +36,23 @@ class CGTownInstance;
|
|||||||
extern boost::thread_specific_ptr<CCallback> cb;
|
extern boost::thread_specific_ptr<CCallback> cb;
|
||||||
extern boost::thread_specific_ptr<VCAI> ai;
|
extern boost::thread_specific_ptr<VCAI> ai;
|
||||||
|
|
||||||
|
EvaluationContext::EvaluationContext()
|
||||||
|
: movementCost(0.0),
|
||||||
|
manaCost(0),
|
||||||
|
danger(0),
|
||||||
|
closestWayRatio(1),
|
||||||
|
movementCostByRole(),
|
||||||
|
skillReward(0),
|
||||||
|
goldReward(0),
|
||||||
|
goldCost(0),
|
||||||
|
armyReward(0),
|
||||||
|
armyLossPersentage(0),
|
||||||
|
heroRole(HeroRole::SCOUT),
|
||||||
|
turn(0),
|
||||||
|
strategicalValue(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
PriorityEvaluator::~PriorityEvaluator()
|
PriorityEvaluator::~PriorityEvaluator()
|
||||||
{
|
{
|
||||||
delete engine;
|
delete engine;
|
||||||
@ -430,46 +447,59 @@ int32_t getGoldReward(const CGObjectInstance * target, const CGHeroInstance * he
|
|||||||
class ExecuteHeroChainEvaluationContextBuilder : public IEvaluationContextBuilder
|
class ExecuteHeroChainEvaluationContextBuilder : public IEvaluationContextBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual Goals::EvaluationContext buildEvaluationContext(Goals::TSubgoal task) const override
|
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal task) const override
|
||||||
{
|
{
|
||||||
|
if(task->goalType != Goals::EXECUTE_HERO_CHAIN)
|
||||||
|
return;
|
||||||
|
|
||||||
Goals::ExecuteHeroChain & chain = dynamic_cast<Goals::ExecuteHeroChain &>(*task);
|
Goals::ExecuteHeroChain & chain = dynamic_cast<Goals::ExecuteHeroChain &>(*task);
|
||||||
auto evaluationContext = task->evaluationContext;
|
const AIPath & path = chain.getPath();
|
||||||
|
|
||||||
|
vstd::amax(evaluationContext.danger, path.getTotalDanger());
|
||||||
|
evaluationContext.movementCost += path.movementCost();
|
||||||
|
evaluationContext.closestWayRatio = chain.closestWayRatio;
|
||||||
|
|
||||||
|
for(auto & node : path.nodes)
|
||||||
|
{
|
||||||
|
auto role = ai->ah->getHeroRole(node.targetHero);
|
||||||
|
|
||||||
|
evaluationContext.movementCostByRole[role] += node.cost;
|
||||||
|
}
|
||||||
|
|
||||||
auto heroPtr = task->hero;
|
auto heroPtr = task->hero;
|
||||||
const CGObjectInstance * target = cb->getObj((ObjectInstanceID)task->objid, false);
|
const CGObjectInstance * target = cb->getObj((ObjectInstanceID)task->objid, false);
|
||||||
auto day = cb->getDate(Date::DAY);
|
auto day = cb->getDate(Date::DAY);
|
||||||
auto hero = heroPtr.get();
|
auto hero = heroPtr.get();
|
||||||
bool checkGold = evaluationContext.danger == 0;
|
bool checkGold = evaluationContext.danger == 0;
|
||||||
auto army = chain.getPath().heroArmy;
|
auto army = path.heroArmy;
|
||||||
|
|
||||||
evaluationContext.armyLossPersentage = task->evaluationContext.armyLoss / (double)task->evaluationContext.heroStrength;
|
vstd::amax(evaluationContext.armyLossPersentage, path.getTotalArmyLoss() / (double)path.getHeroStrength());
|
||||||
evaluationContext.heroRole = ai->ah->getHeroRole(heroPtr);
|
vstd::amax(evaluationContext.heroRole, ai->ah->getHeroRole(heroPtr));
|
||||||
evaluationContext.goldReward = getGoldReward(target, hero);
|
evaluationContext.goldReward += getGoldReward(target, hero);
|
||||||
evaluationContext.armyReward = getArmyReward(target, hero, army, checkGold);
|
evaluationContext.armyReward += getArmyReward(target, hero, army, checkGold);
|
||||||
evaluationContext.skillReward = getSkillReward(target, hero, evaluationContext.heroRole);
|
evaluationContext.skillReward += getSkillReward(target, hero, evaluationContext.heroRole);
|
||||||
evaluationContext.strategicalValue += getStrategicalValue(target);
|
evaluationContext.strategicalValue += getStrategicalValue(target);
|
||||||
evaluationContext.goldCost = getGoldCost(target, hero, army);
|
evaluationContext.goldCost += getGoldCost(target, hero, army);
|
||||||
evaluationContext.turn = chain.getPath().turn();
|
vstd::amax(evaluationContext.turn, path.turn());
|
||||||
|
|
||||||
return evaluationContext;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class BuildThisEvaluationContextBuilder : public IEvaluationContextBuilder
|
class BuildThisEvaluationContextBuilder : public IEvaluationContextBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual Goals::EvaluationContext buildEvaluationContext(Goals::TSubgoal task) const override
|
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal task) const override
|
||||||
{
|
{
|
||||||
Goals::EvaluationContext evaluationContext;
|
if(task->goalType != Goals::BUILD_STRUCTURE)
|
||||||
|
return;
|
||||||
|
|
||||||
Goals::BuildThis & buildThis = dynamic_cast<Goals::BuildThis &>(*task);
|
Goals::BuildThis & buildThis = dynamic_cast<Goals::BuildThis &>(*task);
|
||||||
auto & bi = buildThis.buildingInfo;
|
auto & bi = buildThis.buildingInfo;
|
||||||
|
|
||||||
evaluationContext.goldReward = 7 * bi.dailyIncome[Res::GOLD] / 2; // 7 day income but half we already have
|
evaluationContext.goldReward += 7 * bi.dailyIncome[Res::GOLD] / 2; // 7 day income but half we already have
|
||||||
evaluationContext.heroRole = HeroRole::MAIN;
|
evaluationContext.heroRole = HeroRole::MAIN;
|
||||||
evaluationContext.movementCostByRole[evaluationContext.heroRole] = bi.prerequisitesCount;
|
evaluationContext.movementCostByRole[evaluationContext.heroRole] += bi.prerequisitesCount;
|
||||||
evaluationContext.armyReward = 0;
|
evaluationContext.strategicalValue += buildThis.townInfo.armyScore / 50000.0;
|
||||||
evaluationContext.strategicalValue = buildThis.townInfo.armyScore / 50000.0;
|
evaluationContext.goldCost += bi.buildCostWithPrerequisits[Res::GOLD];
|
||||||
evaluationContext.goldCost = bi.buildCostWithPrerequisits[Res::GOLD];
|
|
||||||
|
|
||||||
if(bi.creatureID != CreatureID::NONE)
|
if(bi.creatureID != CreatureID::NONE)
|
||||||
{
|
{
|
||||||
@ -477,38 +507,56 @@ public:
|
|||||||
|
|
||||||
if(bi.baseCreatureID == bi.creatureID)
|
if(bi.baseCreatureID == bi.creatureID)
|
||||||
{
|
{
|
||||||
evaluationContext.armyReward = ai->ah->evaluateStackPower(bi.creatureID.toCreature(), bi.creatureGrows);
|
evaluationContext.armyReward += ai->ah->evaluateStackPower(bi.creatureID.toCreature(), bi.creatureGrows);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
auto creaturesToUpgrade = ai->ah->getTotalCreaturesAvailable(bi.baseCreatureID);
|
{
|
||||||
auto upgradedPower = ai->ah->evaluateStackPower(bi.creatureID.toCreature(), creaturesToUpgrade.count);
|
auto creaturesToUpgrade = ai->ah->getTotalCreaturesAvailable(bi.baseCreatureID);
|
||||||
|
auto upgradedPower = ai->ah->evaluateStackPower(bi.creatureID.toCreature(), creaturesToUpgrade.count);
|
||||||
|
|
||||||
evaluationContext.armyReward = upgradedPower - creaturesToUpgrade.power;
|
evaluationContext.armyReward += upgradedPower - creaturesToUpgrade.power;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
evaluationContext.strategicalValue = ai->nullkiller->buildAnalyzer->getGoldPreasure() * evaluationContext.goldReward / 2200.0f;
|
evaluationContext.strategicalValue += ai->nullkiller->buildAnalyzer->getGoldPreasure() * evaluationContext.goldReward / 2200.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
return evaluationContext;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PriorityEvaluator::PriorityEvaluator()
|
PriorityEvaluator::PriorityEvaluator()
|
||||||
{
|
{
|
||||||
initVisitTile();
|
initVisitTile();
|
||||||
evaluationContextBuilders[Goals::EXECUTE_HERO_CHAIN] = std::make_shared<ExecuteHeroChainEvaluationContextBuilder>();
|
evaluationContextBuilders.push_back(std::make_shared<ExecuteHeroChainEvaluationContextBuilder>());
|
||||||
evaluationContextBuilders[Goals::BUILD_STRUCTURE] = std::make_shared<BuildThisEvaluationContextBuilder>();
|
evaluationContextBuilders.push_back(std::make_shared<BuildThisEvaluationContextBuilder>());
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::EvaluationContext PriorityEvaluator::buildEvaluationContext(Goals::TSubgoal goal) const
|
EvaluationContext PriorityEvaluator::buildEvaluationContext(Goals::TSubgoal goal) const
|
||||||
{
|
{
|
||||||
auto builder = evaluationContextBuilders.find(goal->goalType);
|
Goals::TGoalVec parts;
|
||||||
|
EvaluationContext context;
|
||||||
|
|
||||||
if(builder == evaluationContextBuilders.end())
|
if(goal->goalType == Goals::COMPOSITION)
|
||||||
return goal->evaluationContext;
|
{
|
||||||
|
parts = goal->decompose();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parts.push_back(goal);
|
||||||
|
}
|
||||||
|
|
||||||
return builder->second->buildEvaluationContext(goal);
|
for(auto goal : parts)
|
||||||
|
{
|
||||||
|
context.strategicalValue += goal->strategicalValue;
|
||||||
|
context.goldCost += goal->goldCost;
|
||||||
|
|
||||||
|
for(auto builder : evaluationContextBuilders)
|
||||||
|
{
|
||||||
|
builder->buildEvaluationContext(context, goal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// distance
|
/// distance
|
||||||
|
@ -11,10 +11,29 @@
|
|||||||
#include "fl/Headers.h"
|
#include "fl/Headers.h"
|
||||||
#include "../Goals/Goals.h"
|
#include "../Goals/Goals.h"
|
||||||
|
|
||||||
|
struct DLL_EXPORT EvaluationContext
|
||||||
|
{
|
||||||
|
float movementCost;
|
||||||
|
std::map<HeroRole, float> movementCostByRole;
|
||||||
|
int manaCost;
|
||||||
|
uint64_t danger;
|
||||||
|
float closestWayRatio;
|
||||||
|
float armyLossPersentage;
|
||||||
|
float armyReward;
|
||||||
|
int32_t goldReward;
|
||||||
|
int32_t goldCost;
|
||||||
|
float skillReward;
|
||||||
|
float strategicalValue;
|
||||||
|
HeroRole heroRole;
|
||||||
|
uint8_t turn;
|
||||||
|
|
||||||
|
EvaluationContext();
|
||||||
|
};
|
||||||
|
|
||||||
class IEvaluationContextBuilder
|
class IEvaluationContextBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual Goals::EvaluationContext buildEvaluationContext(Goals::TSubgoal goal) const = 0;
|
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal goal) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PriorityEvaluator
|
class PriorityEvaluator
|
||||||
@ -43,7 +62,7 @@ private:
|
|||||||
fl::InputVariable * goldPreasureVariable;
|
fl::InputVariable * goldPreasureVariable;
|
||||||
fl::InputVariable * goldCostVariable;
|
fl::InputVariable * goldCostVariable;
|
||||||
fl::OutputVariable * value;
|
fl::OutputVariable * value;
|
||||||
std::map<Goals::EGoals, std::shared_ptr<IEvaluationContextBuilder>> evaluationContextBuilders;
|
std::vector<std::shared_ptr<IEvaluationContextBuilder>> evaluationContextBuilders;
|
||||||
|
|
||||||
Goals::EvaluationContext buildEvaluationContext(Goals::TSubgoal goal) const;
|
EvaluationContext buildEvaluationContext(Goals::TSubgoal goal) const;
|
||||||
};
|
};
|
||||||
|
@ -33,7 +33,7 @@ TTask Goals::taskptr(const AbstractGoal & tmp)
|
|||||||
{
|
{
|
||||||
TTask ptr;
|
TTask ptr;
|
||||||
|
|
||||||
if(!tmp.isElementar)
|
if(!tmp.isElementar())
|
||||||
throw cannotFulfillGoalException(tmp.toString() + " is not elementar");
|
throw cannotFulfillGoalException(tmp.toString() + " is not elementar");
|
||||||
|
|
||||||
ptr.reset(dynamic_cast<ITask *>(tmp.clone()));
|
ptr.reset(dynamic_cast<ITask *>(tmp.clone()));
|
||||||
@ -46,30 +46,6 @@ std::string AbstractGoal::toString() const //TODO: virtualize
|
|||||||
std::string desc;
|
std::string desc;
|
||||||
switch(goalType)
|
switch(goalType)
|
||||||
{
|
{
|
||||||
case INVALID:
|
|
||||||
return "INVALID";
|
|
||||||
case WIN:
|
|
||||||
return "WIN";
|
|
||||||
case CONQUER:
|
|
||||||
return "CONQUER";
|
|
||||||
case BUILD:
|
|
||||||
return "BUILD";
|
|
||||||
case EXPLORE:
|
|
||||||
desc = "EXPLORE";
|
|
||||||
break;
|
|
||||||
case GATHER_ARMY:
|
|
||||||
desc = "GATHER ARMY";
|
|
||||||
break;
|
|
||||||
case BUY_ARMY:
|
|
||||||
return "BUY ARMY";
|
|
||||||
break;
|
|
||||||
case BOOST_HERO:
|
|
||||||
desc = "BOOST_HERO (unsupported)";
|
|
||||||
break;
|
|
||||||
case RECRUIT_HERO:
|
|
||||||
return "RECRUIT HERO";
|
|
||||||
case BUILD_STRUCTURE:
|
|
||||||
return "BUILD STRUCTURE";
|
|
||||||
case COLLECT_RES:
|
case COLLECT_RES:
|
||||||
desc = "COLLECT RESOURCE " + GameConstants::RESOURCE_NAMES[resID] + " (" + boost::lexical_cast<std::string>(value) + ")";
|
desc = "COLLECT RESOURCE " + GameConstants::RESOURCE_NAMES[resID] + " (" + boost::lexical_cast<std::string>(value) + ")";
|
||||||
break;
|
break;
|
||||||
@ -83,32 +59,9 @@ std::string AbstractGoal::toString() const //TODO: virtualize
|
|||||||
case GATHER_TROOPS:
|
case GATHER_TROOPS:
|
||||||
desc = "GATHER TROOPS";
|
desc = "GATHER TROOPS";
|
||||||
break;
|
break;
|
||||||
case VISIT_OBJ:
|
|
||||||
{
|
|
||||||
auto obj = cb->getObjInstance(ObjectInstanceID(objid));
|
|
||||||
if(obj)
|
|
||||||
desc = "VISIT OBJ " + obj->getObjectName();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FIND_OBJ:
|
|
||||||
desc = "FIND OBJ " + boost::lexical_cast<std::string>(objid);
|
|
||||||
break;
|
|
||||||
case VISIT_HERO:
|
|
||||||
{
|
|
||||||
auto obj = cb->getObjInstance(ObjectInstanceID(objid));
|
|
||||||
if(obj)
|
|
||||||
desc = "VISIT HERO " + obj->getObjectName();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GET_ART_TYPE:
|
case GET_ART_TYPE:
|
||||||
desc = "GET ARTIFACT OF TYPE " + VLC->arth->artifacts[aid]->Name();
|
desc = "GET ARTIFACT OF TYPE " + VLC->arth->artifacts[aid]->Name();
|
||||||
break;
|
break;
|
||||||
case VISIT_TILE:
|
|
||||||
desc = "VISIT TILE " + tile.toString();
|
|
||||||
break;
|
|
||||||
case CLEAR_WAY_TO:
|
|
||||||
desc = "CLEAR WAY TO " + tile.toString();
|
|
||||||
break;
|
|
||||||
case DIG_AT_TILE:
|
case DIG_AT_TILE:
|
||||||
desc = "DIG AT TILE " + tile.toString();
|
desc = "DIG AT TILE " + tile.toString();
|
||||||
break;
|
break;
|
||||||
@ -134,23 +87,4 @@ bool TSubgoal::operator==(const TSubgoal & rhs) const
|
|||||||
bool AbstractGoal::invalid() const
|
bool AbstractGoal::invalid() const
|
||||||
{
|
{
|
||||||
return goalType == EGoals::INVALID;
|
return goalType == EGoals::INVALID;
|
||||||
}
|
|
||||||
|
|
||||||
EvaluationContext::EvaluationContext()
|
|
||||||
: movementCost(0.0),
|
|
||||||
manaCost(0),
|
|
||||||
danger(0),
|
|
||||||
closestWayRatio(1),
|
|
||||||
armyLoss(0),
|
|
||||||
heroStrength(0),
|
|
||||||
movementCostByRole(),
|
|
||||||
skillReward(0),
|
|
||||||
goldReward(0),
|
|
||||||
goldCost(0),
|
|
||||||
armyReward(0),
|
|
||||||
armyLossPersentage(0),
|
|
||||||
heroRole(HeroRole::SCOUT),
|
|
||||||
turn(0),
|
|
||||||
strategicalValue(0)
|
|
||||||
{
|
|
||||||
}
|
}
|
@ -29,7 +29,6 @@ namespace Goals
|
|||||||
class CollectRes;
|
class CollectRes;
|
||||||
class BuyArmy;
|
class BuyArmy;
|
||||||
class BuildBoat;
|
class BuildBoat;
|
||||||
class ClearWayTo;
|
|
||||||
class Invalid;
|
class Invalid;
|
||||||
class Trade;
|
class Trade;
|
||||||
class AdventureSpellCast;
|
class AdventureSpellCast;
|
||||||
@ -42,18 +41,17 @@ namespace Goals
|
|||||||
EXPLORE, GATHER_ARMY,
|
EXPLORE, GATHER_ARMY,
|
||||||
BOOST_HERO,
|
BOOST_HERO,
|
||||||
RECRUIT_HERO,
|
RECRUIT_HERO,
|
||||||
|
RECRUIT_HERO_BEHAVIOR,
|
||||||
BUILD_STRUCTURE, //if hero set, then in visited town
|
BUILD_STRUCTURE, //if hero set, then in visited town
|
||||||
COLLECT_RES,
|
COLLECT_RES,
|
||||||
GATHER_TROOPS, // val of creatures with objid
|
GATHER_TROOPS, // val of creatures with objid
|
||||||
|
|
||||||
VISIT_OBJ, //visit or defeat or collect the object
|
CAPTURE_OBJECTS,
|
||||||
FIND_OBJ, //find and visit any obj with objid + resid //TODO: consider universal subid for various types (aid, bid)
|
|
||||||
VISIT_HERO, //heroes can move around - set goal abstract and track hero every turn
|
|
||||||
|
|
||||||
GET_ART_TYPE,
|
GET_ART_TYPE,
|
||||||
|
|
||||||
VISIT_TILE, //tile, in conjunction with hero elementar; assumes tile is reachable
|
DEFENCE,
|
||||||
CLEAR_WAY_TO,
|
STARTUP,
|
||||||
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
|
||||||
@ -62,7 +60,8 @@ namespace Goals
|
|||||||
ADVENTURE_SPELL_CAST,
|
ADVENTURE_SPELL_CAST,
|
||||||
EXECUTE_HERO_CHAIN,
|
EXECUTE_HERO_CHAIN,
|
||||||
EXCHANGE_SWAP_TOWN_HEROES,
|
EXCHANGE_SWAP_TOWN_HEROES,
|
||||||
DISMISS_HERO
|
DISMISS_HERO,
|
||||||
|
COMPOSITION
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT TSubgoal : public std::shared_ptr<AbstractGoal>
|
class DLL_EXPORT TSubgoal : public std::shared_ptr<AbstractGoal>
|
||||||
@ -89,34 +88,14 @@ namespace Goals
|
|||||||
|
|
||||||
DLL_EXPORT TSubgoal sptr(const AbstractGoal & tmp);
|
DLL_EXPORT TSubgoal sptr(const AbstractGoal & tmp);
|
||||||
DLL_EXPORT TTask taskptr(const AbstractGoal & tmp);
|
DLL_EXPORT TTask taskptr(const AbstractGoal & tmp);
|
||||||
|
|
||||||
struct DLL_EXPORT EvaluationContext
|
|
||||||
{
|
|
||||||
float movementCost;
|
|
||||||
std::map<HeroRole, float> movementCostByRole;
|
|
||||||
int manaCost;
|
|
||||||
uint64_t danger;
|
|
||||||
float closestWayRatio;
|
|
||||||
uint64_t armyLoss;
|
|
||||||
uint64_t heroStrength;
|
|
||||||
float armyLossPersentage;
|
|
||||||
float armyReward;
|
|
||||||
int32_t goldReward;
|
|
||||||
int32_t goldCost;
|
|
||||||
float skillReward;
|
|
||||||
float strategicalValue;
|
|
||||||
HeroRole heroRole;
|
|
||||||
uint8_t turn;
|
|
||||||
|
|
||||||
EvaluationContext();
|
|
||||||
};
|
|
||||||
|
|
||||||
class DLL_EXPORT AbstractGoal
|
class DLL_EXPORT AbstractGoal
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool isElementar; VSETTER(bool, isElementar)
|
|
||||||
bool isAbstract; VSETTER(bool, isAbstract)
|
bool isAbstract; VSETTER(bool, isAbstract)
|
||||||
int value; VSETTER(int, value)
|
int value; VSETTER(int, value)
|
||||||
|
float strategicalValue; VSETTER(float, strategicalValue)
|
||||||
|
ui64 goldCost; VSETTER(ui64, goldCost)
|
||||||
int resID; VSETTER(int, resID)
|
int resID; VSETTER(int, resID)
|
||||||
int objid; VSETTER(int, objid)
|
int objid; VSETTER(int, objid)
|
||||||
int aid; VSETTER(int, aid)
|
int aid; VSETTER(int, aid)
|
||||||
@ -125,12 +104,11 @@ namespace Goals
|
|||||||
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)
|
TSubgoal parent; VSETTER(TSubgoal, parent)
|
||||||
EvaluationContext evaluationContext; VSETTER(EvaluationContext, evaluationContext)
|
//EvaluationContext evaluationContext; VSETTER(EvaluationContext, evaluationContext)
|
||||||
|
|
||||||
AbstractGoal(EGoals goal = EGoals::INVALID)
|
AbstractGoal(EGoals goal = EGoals::INVALID)
|
||||||
: goalType(goal), evaluationContext()
|
: goalType(goal), hero()
|
||||||
{
|
{
|
||||||
isElementar = false;
|
|
||||||
isAbstract = false;
|
isAbstract = false;
|
||||||
value = 0;
|
value = 0;
|
||||||
aid = -1;
|
aid = -1;
|
||||||
@ -139,6 +117,8 @@ namespace Goals
|
|||||||
tile = int3(-1, -1, -1);
|
tile = int3(-1, -1, -1);
|
||||||
town = nullptr;
|
town = nullptr;
|
||||||
bid = -1;
|
bid = -1;
|
||||||
|
strategicalValue = 0;
|
||||||
|
goldCost = 0;
|
||||||
}
|
}
|
||||||
virtual ~AbstractGoal() {}
|
virtual ~AbstractGoal() {}
|
||||||
//FIXME: abstract goal should be abstract, but serializer fails to instantiate subgoals in such case
|
//FIXME: abstract goal should be abstract, but serializer fails to instantiate subgoals in such case
|
||||||
@ -159,6 +139,8 @@ namespace Goals
|
|||||||
bool invalid() const;
|
bool invalid() const;
|
||||||
|
|
||||||
virtual bool operator==(const AbstractGoal & g) const;
|
virtual bool operator==(const AbstractGoal & g) const;
|
||||||
|
|
||||||
|
virtual bool isElementar() const { return false; }
|
||||||
|
|
||||||
bool operator!=(const AbstractGoal & g) const
|
bool operator!=(const AbstractGoal & g) const
|
||||||
{
|
{
|
||||||
@ -167,6 +149,9 @@ namespace Goals
|
|||||||
|
|
||||||
template<typename Handler> void serialize(Handler & h, const int version)
|
template<typename Handler> void serialize(Handler & h, const int version)
|
||||||
{
|
{
|
||||||
|
float priority;
|
||||||
|
bool isElementar;
|
||||||
|
|
||||||
h & goalType;
|
h & goalType;
|
||||||
h & isElementar;
|
h & isElementar;
|
||||||
h & isAbstract;
|
h & isAbstract;
|
||||||
@ -187,9 +172,12 @@ namespace Goals
|
|||||||
public:
|
public:
|
||||||
float priority;
|
float priority;
|
||||||
|
|
||||||
|
ITask() : priority(0) {}
|
||||||
|
|
||||||
///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) = 0; //unhandled goal will report standard error
|
virtual void accept(VCAI * ai) = 0; //unhandled goal will report standard error
|
||||||
virtual std::string toString() const = 0;
|
virtual std::string toString() const = 0;
|
||||||
|
virtual ~ITask() {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -26,24 +26,24 @@ bool BuildBoat::operator==(const BuildBoat & other) const
|
|||||||
{
|
{
|
||||||
return shipyard->o->id == other.shipyard->o->id;
|
return shipyard->o->id == other.shipyard->o->id;
|
||||||
}
|
}
|
||||||
|
//
|
||||||
TSubgoal BuildBoat::decomposeSingle() const
|
//TSubgoal BuildBoat::decomposeSingle() const
|
||||||
{
|
//{
|
||||||
if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
// if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
||||||
{
|
// {
|
||||||
return sptr(CaptureObjectsBehavior(shipyard->o));
|
// return sptr(CaptureObjectsBehavior(shipyard->o));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if(shipyard->shipyardStatus() != IShipyard::GOOD)
|
// if(shipyard->shipyardStatus() != IShipyard::GOOD)
|
||||||
{
|
// {
|
||||||
throw cannotFulfillGoalException("Shipyard is busy.");
|
// throw cannotFulfillGoalException("Shipyard is busy.");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
TResources boatCost;
|
// TResources boatCost;
|
||||||
shipyard->getBoatCost(boatCost);
|
// shipyard->getBoatCost(boatCost);
|
||||||
|
//
|
||||||
return iAmElementar();
|
// return iAmElementar();
|
||||||
}
|
//}
|
||||||
|
|
||||||
void BuildBoat::accept(VCAI * ai)
|
void BuildBoat::accept(VCAI * ai)
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,6 @@ namespace Goals
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const IShipyard * shipyard;
|
const IShipyard * shipyard;
|
||||||
TSubgoal decomposeSingle() const override;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BuildBoat(const IShipyard * shipyard)
|
BuildBoat(const IShipyard * shipyard)
|
||||||
|
@ -32,4 +32,23 @@ bool BuildThis::operator==(const BuildThis & other) const
|
|||||||
std::string BuildThis::toString() const
|
std::string BuildThis::toString() const
|
||||||
{
|
{
|
||||||
return "Build " + buildingInfo.name + "(" + std::to_string(bid) + ") in " + town->name;
|
return "Build " + buildingInfo.name + "(" + std::to_string(bid) + ") in " + town->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildThis::accept(VCAI * ai)
|
||||||
|
{
|
||||||
|
auto b = BuildingID(bid);
|
||||||
|
|
||||||
|
if(town)
|
||||||
|
{
|
||||||
|
if(cb->canBuildStructure(town, b) == EBuildingState::ALLOWED)
|
||||||
|
{
|
||||||
|
logAi->debug("Player %d will build %s in town of %s at %s",
|
||||||
|
ai->playerID, town->town->buildings.at(b)->Name(), town->name, town->pos.toString());
|
||||||
|
cb->buildBuilding(town, b);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw cannotFulfillGoalException("Cannot build a given structure!");
|
||||||
}
|
}
|
@ -49,5 +49,6 @@ namespace Goals
|
|||||||
}
|
}
|
||||||
virtual bool operator==(const BuildThis & other) const override;
|
virtual bool operator==(const BuildThis & other) const override;
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
void accept(VCAI * ai) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -28,4 +28,49 @@ bool BuyArmy::operator==(const BuyArmy & other) const
|
|||||||
std::string BuyArmy::toString() const
|
std::string BuyArmy::toString() const
|
||||||
{
|
{
|
||||||
return "Buy army at " + town->name;
|
return "Buy army at " + town->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuyArmy::accept(VCAI * ai)
|
||||||
|
{
|
||||||
|
ui64 valueBought = 0;
|
||||||
|
//buy the stacks with largest AI value
|
||||||
|
|
||||||
|
auto upgradeSuccessfull = ai->makePossibleUpgrades(town);
|
||||||
|
|
||||||
|
auto armyToBuy = ai->ah->getArmyAvailableToBuy(town->getUpperArmy(), town);
|
||||||
|
|
||||||
|
if(armyToBuy.empty())
|
||||||
|
{
|
||||||
|
if(upgradeSuccessfull)
|
||||||
|
return;
|
||||||
|
|
||||||
|
throw cannotFulfillGoalException("No creatures to buy.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; valueBought < value && i < armyToBuy.size(); i++)
|
||||||
|
{
|
||||||
|
auto res = cb->getResourceAmount();
|
||||||
|
auto & ci = armyToBuy[i];
|
||||||
|
|
||||||
|
if(objid != -1 && ci.creID != objid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
vstd::amin(ci.count, res / ci.cre->cost);
|
||||||
|
|
||||||
|
if(ci.count)
|
||||||
|
{
|
||||||
|
cb->recruitCreatures(town, town->getUpperArmy(), ci.creID, ci.count, ci.level);
|
||||||
|
valueBought += ci.count * ci.cre->AIValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!valueBought)
|
||||||
|
{
|
||||||
|
throw cannotFulfillGoalException("No creatures to buy.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(town->visitingHero)
|
||||||
|
{
|
||||||
|
ai->moveHeroToTile(town->visitablePos(), town->visitingHero.get());
|
||||||
|
}
|
||||||
}
|
}
|
@ -36,5 +36,7 @@ namespace Goals
|
|||||||
virtual bool operator==(const BuyArmy & other) const override;
|
virtual bool operator==(const BuyArmy & other) const override;
|
||||||
|
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
|
||||||
|
virtual void accept(VCAI * ai) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ namespace Goals
|
|||||||
public:
|
public:
|
||||||
CGoal<T>(EGoals goal = INVALID) : AbstractGoal(goal)
|
CGoal<T>(EGoals goal = INVALID) : AbstractGoal(goal)
|
||||||
{
|
{
|
||||||
isElementar = false;
|
|
||||||
isAbstract = true;
|
isAbstract = true;
|
||||||
value = 0;
|
value = 0;
|
||||||
aid = -1;
|
aid = -1;
|
||||||
@ -33,7 +32,6 @@ namespace Goals
|
|||||||
town = nullptr;
|
town = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
OSETTER(bool, isElementar)
|
|
||||||
OSETTER(bool, isAbstract)
|
OSETTER(bool, isAbstract)
|
||||||
OSETTER(int, value)
|
OSETTER(int, value)
|
||||||
OSETTER(int, resID)
|
OSETTER(int, resID)
|
||||||
@ -48,15 +46,6 @@ namespace Goals
|
|||||||
{
|
{
|
||||||
return new T(static_cast<T const &>(*this)); //casting enforces template instantiation
|
return new T(static_cast<T const &>(*this)); //casting enforces template instantiation
|
||||||
}
|
}
|
||||||
TSubgoal iAmElementar() const
|
|
||||||
{
|
|
||||||
TSubgoal ptr;
|
|
||||||
|
|
||||||
ptr.reset(clone());
|
|
||||||
ptr->setisElementar(true);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
template<typename Handler> void serialize(Handler & h, const int version)
|
template<typename Handler> void serialize(Handler & h, const int version)
|
||||||
{
|
{
|
||||||
h & static_cast<AbstractGoal &>(*this);
|
h & static_cast<AbstractGoal &>(*this);
|
||||||
@ -76,7 +65,12 @@ namespace Goals
|
|||||||
|
|
||||||
virtual TGoalVec decompose() const override
|
virtual TGoalVec decompose() const override
|
||||||
{
|
{
|
||||||
return {decomposeSingle()};
|
TSubgoal single = decomposeSingle();
|
||||||
|
|
||||||
|
if(single->invalid())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return {single};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -89,18 +83,20 @@ namespace Goals
|
|||||||
template<typename T> class DLL_EXPORT ElementarGoal : public CGoal<T>, public ITask
|
template<typename T> class DLL_EXPORT ElementarGoal : public CGoal<T>, public ITask
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ElementarGoal<T>(EGoals goal = INVALID) : CGoal(goal)
|
ElementarGoal<T>(EGoals goal = INVALID) : CGoal(goal), ITask()
|
||||||
{
|
{
|
||||||
priority = 0;
|
|
||||||
isElementar = true;
|
|
||||||
isAbstract = false;
|
isAbstract = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ElementarGoal<T>(const ElementarGoal<T> & other) : CGoal(other), ITask(other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
///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) override //unhandled goal will report standard error
|
virtual void accept(VCAI * ai) override //unhandled goal will report standard error
|
||||||
{
|
{
|
||||||
ai->tryRealize(*this);
|
ai->tryRealize(*((T *)this));
|
||||||
}
|
}
|
||||||
|
|
||||||
T & setpriority(float p)
|
T & setpriority(float p)
|
||||||
@ -109,6 +105,11 @@ namespace Goals
|
|||||||
|
|
||||||
return *((T *)this);
|
return *((T *)this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool isElementar() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT Invalid : public ElementarGoal<Invalid>
|
class DLL_EXPORT Invalid : public ElementarGoal<Invalid>
|
||||||
|
114
AI/Nullkiller/Goals/Composition.cpp
Normal file
114
AI/Nullkiller/Goals/Composition.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* BuildThis.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 "Composition.h"
|
||||||
|
#include "../VCAI.h"
|
||||||
|
#include "../AIUtility.h"
|
||||||
|
#include "../AIhelper.h"
|
||||||
|
#include "../FuzzyHelper.h"
|
||||||
|
#include "../../../lib/mapping/CMap.h" //for victory conditions
|
||||||
|
#include "../../../lib/CPathfinder.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 Composition::operator==(const Composition & other) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Composition::toString() const
|
||||||
|
{
|
||||||
|
std::string result = "Composition";
|
||||||
|
|
||||||
|
for(auto goal : subtasks)
|
||||||
|
{
|
||||||
|
result += " " + goal->toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Composition::accept(VCAI * ai)
|
||||||
|
{
|
||||||
|
taskptr(*subtasks.back())->accept(ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec Composition::decompose() const
|
||||||
|
{
|
||||||
|
if(isElementar())
|
||||||
|
return subtasks;
|
||||||
|
|
||||||
|
auto tasks = subtasks;
|
||||||
|
tasks.pop_back();
|
||||||
|
|
||||||
|
TSubgoal last = subtasks.back();
|
||||||
|
auto decomposed = last->decompose();
|
||||||
|
TGoalVec result;
|
||||||
|
|
||||||
|
for(TSubgoal goal : decomposed)
|
||||||
|
{
|
||||||
|
if(goal->invalid() || goal == last || vstd::contains(tasks, goal))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto newComposition = Composition(tasks);
|
||||||
|
|
||||||
|
if(goal->goalType == COMPOSITION)
|
||||||
|
{
|
||||||
|
Composition & other = dynamic_cast<Composition &>(*goal);
|
||||||
|
bool cancel = false;
|
||||||
|
|
||||||
|
for(auto goal : other.subtasks)
|
||||||
|
{
|
||||||
|
if(goal == last || vstd::contains(tasks, goal))
|
||||||
|
{
|
||||||
|
cancel = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
newComposition.addNext(goal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cancel)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newComposition.addNext(goal);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push_back(sptr(newComposition));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Composition & Composition::addNext(AbstractGoal & goal)
|
||||||
|
{
|
||||||
|
return addNext(sptr(goal));
|
||||||
|
}
|
||||||
|
|
||||||
|
Composition & Composition::addNext(TSubgoal goal)
|
||||||
|
{
|
||||||
|
subtasks.push_back(goal);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Composition::isElementar() const
|
||||||
|
{
|
||||||
|
return subtasks.back()->isElementar();
|
||||||
|
}
|
40
AI/Nullkiller/Goals/Composition.h
Normal file
40
AI/Nullkiller/Goals/Composition.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* BuildThis.h, 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CGoal.h"
|
||||||
|
|
||||||
|
namespace Goals
|
||||||
|
{
|
||||||
|
class DLL_EXPORT Composition : public ElementarGoal<Composition>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
TGoalVec subtasks;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Composition()
|
||||||
|
: ElementarGoal(Goals::COMPOSITION), subtasks()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Composition(TGoalVec subtasks)
|
||||||
|
: ElementarGoal(Goals::COMPOSITION), subtasks(subtasks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool operator==(const Composition & other) const override;
|
||||||
|
virtual std::string toString() const override;
|
||||||
|
void accept(VCAI * ai) override;
|
||||||
|
Composition & addNext(AbstractGoal & goal);
|
||||||
|
Composition & addNext(TSubgoal goal);
|
||||||
|
virtual TGoalVec decompose() const override;
|
||||||
|
virtual bool isElementar() const override;
|
||||||
|
};
|
||||||
|
}
|
@ -9,7 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "DigAtTile.h"
|
#include "DigAtTile.h"
|
||||||
#include "VisitTile.h"
|
|
||||||
#include "../VCAI.h"
|
#include "../VCAI.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "ExecuteHeroChain.h"
|
#include "ExecuteHeroChain.h"
|
||||||
#include "VisitTile.h"
|
|
||||||
#include "../VCAI.h"
|
#include "../VCAI.h"
|
||||||
#include "../FuzzyHelper.h"
|
#include "../FuzzyHelper.h"
|
||||||
#include "../AIhelper.h"
|
#include "../AIhelper.h"
|
||||||
@ -26,7 +25,6 @@ using namespace Goals;
|
|||||||
ExecuteHeroChain::ExecuteHeroChain(const AIPath & path, const CGObjectInstance * obj)
|
ExecuteHeroChain::ExecuteHeroChain(const AIPath & path, const CGObjectInstance * obj)
|
||||||
:ElementarGoal(Goals::EXECUTE_HERO_CHAIN), chainPath(path)
|
:ElementarGoal(Goals::EXECUTE_HERO_CHAIN), chainPath(path)
|
||||||
{
|
{
|
||||||
|
|
||||||
hero = path.targetHero;
|
hero = path.targetHero;
|
||||||
tile = path.targetTile();
|
tile = path.targetTile();
|
||||||
|
|
||||||
@ -43,7 +41,10 @@ ExecuteHeroChain::ExecuteHeroChain(const AIPath & path, const CGObjectInstance *
|
|||||||
|
|
||||||
bool ExecuteHeroChain::operator==(const ExecuteHeroChain & other) const
|
bool ExecuteHeroChain::operator==(const ExecuteHeroChain & other) const
|
||||||
{
|
{
|
||||||
return false;
|
return tile == other.tile
|
||||||
|
&& chainPath.targetHero == other.chainPath.targetHero
|
||||||
|
&& chainPath.nodes.size() == other.chainPath.nodes.size()
|
||||||
|
&& chainPath.chainMask == other.chainPath.chainMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecuteHeroChain::accept(VCAI * ai)
|
void ExecuteHeroChain::accept(VCAI * ai)
|
||||||
@ -79,19 +80,13 @@ void ExecuteHeroChain::accept(VCAI * ai)
|
|||||||
|
|
||||||
if(node.specialAction)
|
if(node.specialAction)
|
||||||
{
|
{
|
||||||
if(node.specialAction->canAct(hero))
|
if(node.actionIsBlocked)
|
||||||
{
|
|
||||||
auto specialGoal = node.specialAction->whatToDo(hero);
|
|
||||||
|
|
||||||
if(!specialGoal->isElementar)
|
|
||||||
|
|
||||||
specialGoal->accept(ai);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
throw cannotFulfillGoalException("Path is nondeterministic.");
|
throw cannotFulfillGoalException("Path is nondeterministic.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node.specialAction->execute(hero);
|
||||||
|
|
||||||
if(!heroPtr.validAndSet())
|
if(!heroPtr.validAndSet())
|
||||||
{
|
{
|
||||||
logAi->error("Hero %s was lost trying to execute special action. Exit hero chain.", heroPtr.name);
|
logAi->error("Hero %s was lost trying to execute special action. Exit hero chain.", heroPtr.name);
|
||||||
@ -192,9 +187,9 @@ std::string ExecuteHeroChain::toString() const
|
|||||||
|
|
||||||
bool ExecuteHeroChain::moveHeroToTile(const CGHeroInstance * hero, const int3 & tile)
|
bool ExecuteHeroChain::moveHeroToTile(const CGHeroInstance * hero, const int3 & tile)
|
||||||
{
|
{
|
||||||
if(g.tile == g.hero->visitablePos() && cb->getVisitableObjs(g.hero->visitablePos()).size() < 2)
|
if(tile == hero->visitablePos() && cb->getVisitableObjs(hero->visitablePos()).size() < 2)
|
||||||
{
|
{
|
||||||
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", g.hero->name, g.tile.toString());
|
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", hero->name, tile.toString());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ namespace Goals
|
|||||||
std::string targetName;
|
std::string targetName;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
float closestWayRatio;
|
||||||
|
|
||||||
ExecuteHeroChain(const AIPath & path, const CGObjectInstance * obj = nullptr);
|
ExecuteHeroChain(const AIPath & path, const CGObjectInstance * obj = nullptr);
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "FindObj.h"
|
#include "FindObj.h"
|
||||||
#include "VisitObj.h"
|
|
||||||
#include "../VCAI.h"
|
#include "../VCAI.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
|
||||||
|
@ -11,32 +11,4 @@
|
|||||||
|
|
||||||
#include "CGoal.h"
|
#include "CGoal.h"
|
||||||
|
|
||||||
struct HeroPtr;
|
#error not supported
|
||||||
class VCAI;
|
|
||||||
class FuzzyHelper;
|
|
||||||
|
|
||||||
namespace Goals
|
|
||||||
{
|
|
||||||
class DLL_EXPORT FindObj : public CGoal<FindObj>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FindObj() {} // empty constructor not allowed
|
|
||||||
|
|
||||||
FindObj(int ID)
|
|
||||||
: CGoal(Goals::FIND_OBJ)
|
|
||||||
{
|
|
||||||
objid = ID;
|
|
||||||
resID = -1; //subid unspecified
|
|
||||||
}
|
|
||||||
FindObj(int ID, int subID)
|
|
||||||
: CGoal(Goals::FIND_OBJ)
|
|
||||||
{
|
|
||||||
objid = ID;
|
|
||||||
resID = subID;
|
|
||||||
}
|
|
||||||
virtual bool operator==(const FindObj & other) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
//TSubgoal decomposeSingle() const override;
|
|
||||||
};
|
|
||||||
}
|
|
@ -9,7 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "GetArtOfType.h"
|
#include "GetArtOfType.h"
|
||||||
#include "FindObj.h"
|
|
||||||
#include "../VCAI.h"
|
#include "../VCAI.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
|
||||||
|
@ -20,5 +20,4 @@
|
|||||||
#include "RecruitHero.h"
|
#include "RecruitHero.h"
|
||||||
#include "GetArtOfType.h"
|
#include "GetArtOfType.h"
|
||||||
#include "DigAtTile.h"
|
#include "DigAtTile.h"
|
||||||
#include "FindObj.h"
|
|
||||||
#include "AdventureSpellCast.h"
|
#include "AdventureSpellCast.h"
|
@ -27,4 +27,22 @@ using namespace Goals;
|
|||||||
std::string RecruitHero::toString() const
|
std::string RecruitHero::toString() const
|
||||||
{
|
{
|
||||||
return "Recruit hero at " + town->name;
|
return "Recruit hero at " + town->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecruitHero::accept(VCAI * ai)
|
||||||
|
{
|
||||||
|
auto t = town;
|
||||||
|
|
||||||
|
if(!t) t = ai->findTownWithTavern();
|
||||||
|
|
||||||
|
if(t)
|
||||||
|
{
|
||||||
|
ai->recruitHero(t, true);
|
||||||
|
//TODO try to free way to blocked town
|
||||||
|
//TODO: adventure map tavern or prison?
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw cannotFulfillGoalException("No town to recruit hero!");
|
||||||
|
}
|
||||||
}
|
}
|
@ -39,5 +39,6 @@ namespace Goals
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
void accept(VCAI * ai) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1033,13 +1033,16 @@ void AINodeStorage::fillChainInfo(const AIPathNode * node, AIPath & path, int pa
|
|||||||
pathNode.coord = node->coord;
|
pathNode.coord = node->coord;
|
||||||
pathNode.parentIndex = parentIndex;
|
pathNode.parentIndex = parentIndex;
|
||||||
|
|
||||||
|
if(pathNode.specialAction)
|
||||||
|
{
|
||||||
|
pathNode.actionIsBlocked = !pathNode.specialAction->canAct(node);
|
||||||
|
}
|
||||||
|
|
||||||
parentIndex = path.nodes.size();
|
parentIndex = path.nodes.size();
|
||||||
|
|
||||||
path.nodes.push_back(pathNode);
|
path.nodes.push_back(pathNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
path.specialAction = node->specialAction;
|
|
||||||
|
|
||||||
node = getAINode(node->theNodeBefore);
|
node = getAINode(node->theNodeBefore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1049,15 +1052,15 @@ AIPath::AIPath()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const ISpecialAction> AIPath::getFirstBlockedAction() const
|
std::shared_ptr<const SpecialAction> AIPath::getFirstBlockedAction() const
|
||||||
{
|
{
|
||||||
for(auto node : nodes)
|
for(auto node : nodes)
|
||||||
{
|
{
|
||||||
if(node.specialAction && !node.specialAction->canAct(node.targetHero))
|
if(node.specialAction && node.actionIsBlocked)
|
||||||
return node.specialAction;
|
return node.specialAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::shared_ptr<const ISpecialAction>();
|
return std::shared_ptr<const SpecialAction>();
|
||||||
}
|
}
|
||||||
|
|
||||||
int3 AIPath::firstTileToGet() const
|
int3 AIPath::firstTileToGet() const
|
||||||
|
@ -10,15 +10,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define VCMI_TRACE_PATHFINDER 1
|
#define VCMI_TRACE_PATHFINDER 2
|
||||||
#define AI_TRACE_LEVEL 1
|
#define AI_TRACE_LEVEL 2
|
||||||
|
|
||||||
#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 "../FuzzyHelper.h"
|
#include "../FuzzyHelper.h"
|
||||||
#include "../Goals/AbstractGoal.h"
|
#include "../Goals/AbstractGoal.h"
|
||||||
#include "Actions/ISpecialAction.h"
|
#include "Actions/SpecialAction.h"
|
||||||
#include "Actors.h"
|
#include "Actors.h"
|
||||||
|
|
||||||
struct AIPathNode : public CGPathNode
|
struct AIPathNode : public CGPathNode
|
||||||
@ -27,7 +27,7 @@ struct AIPathNode : public CGPathNode
|
|||||||
uint64_t armyLoss;
|
uint64_t armyLoss;
|
||||||
uint32_t manaCost;
|
uint32_t manaCost;
|
||||||
const AIPathNode * chainOther;
|
const AIPathNode * chainOther;
|
||||||
std::shared_ptr<const ISpecialAction> specialAction;
|
std::shared_ptr<const SpecialAction> specialAction;
|
||||||
const ChainActor * actor;
|
const ChainActor * actor;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,13 +40,13 @@ struct AIPathNodeInfo
|
|||||||
const CGHeroInstance * targetHero;
|
const CGHeroInstance * targetHero;
|
||||||
int parentIndex;
|
int parentIndex;
|
||||||
uint64_t chainMask;
|
uint64_t chainMask;
|
||||||
std::shared_ptr<const ISpecialAction> specialAction;
|
std::shared_ptr<const SpecialAction> specialAction;
|
||||||
|
bool actionIsBlocked;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIPath
|
struct AIPath
|
||||||
{
|
{
|
||||||
std::vector<AIPathNodeInfo> nodes;
|
std::vector<AIPathNodeInfo> nodes;
|
||||||
std::shared_ptr<const ISpecialAction> specialAction;
|
|
||||||
uint64_t targetObjectDanger;
|
uint64_t targetObjectDanger;
|
||||||
uint64_t armyLoss;
|
uint64_t armyLoss;
|
||||||
uint64_t targetObjectArmyLoss;
|
uint64_t targetObjectArmyLoss;
|
||||||
@ -81,7 +81,7 @@ struct AIPath
|
|||||||
|
|
||||||
std::string toString() const;
|
std::string toString() const;
|
||||||
|
|
||||||
std::shared_ptr<const ISpecialAction> getFirstBlockedAction() const;
|
std::shared_ptr<const SpecialAction> getFirstBlockedAction() const;
|
||||||
|
|
||||||
bool containsHero(const CGHeroInstance * hero) const;
|
bool containsHero(const CGHeroInstance * hero) const;
|
||||||
};
|
};
|
||||||
|
@ -9,13 +9,44 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "../../Goals/VisitTile.h"
|
|
||||||
#include "BattleAction.h"
|
#include "BattleAction.h"
|
||||||
|
#include "../../VCAI.h"
|
||||||
|
#include "../../Behaviors/CompleteQuestBehavior.h"
|
||||||
|
#include "../../../../lib/mapping/CMap.h" //for victory conditions
|
||||||
|
|
||||||
|
extern boost::thread_specific_ptr<CCallback> cb;
|
||||||
|
extern boost::thread_specific_ptr<VCAI> ai;
|
||||||
|
|
||||||
namespace AIPathfinding
|
namespace AIPathfinding
|
||||||
{
|
{
|
||||||
Goals::TSubgoal BattleAction::whatToDo(const CGHeroInstance * hero) const
|
void BattleAction::execute(const CGHeroInstance * hero) const
|
||||||
{
|
{
|
||||||
return Goals::sptr(Goals::VisitTile(targetTile).sethero(hero));
|
ai->moveHeroToTile(targetTile, hero);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BattleAction::toString() const
|
||||||
|
{
|
||||||
|
return "Battle at " + targetTile.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QuestAction::canAct(const AIPathNode * node) const
|
||||||
|
{
|
||||||
|
QuestInfo q = questInfo;
|
||||||
|
return q.quest->checkQuest(node->actor->hero);
|
||||||
|
}
|
||||||
|
|
||||||
|
Goals::TSubgoal QuestAction::decompose(const CGHeroInstance * hero) const
|
||||||
|
{
|
||||||
|
return Goals::sptr(Goals::Invalid());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuestAction::execute(const CGHeroInstance * hero) const
|
||||||
|
{
|
||||||
|
ai->moveHeroToTile(questInfo.obj->visitablePos(), hero);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string QuestAction::toString() const
|
||||||
|
{
|
||||||
|
return "Complete Quest";
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,11 +10,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ISpecialAction.h"
|
#include "SpecialAction.h"
|
||||||
|
#include "../../../../lib/CGameState.h"
|
||||||
|
|
||||||
namespace AIPathfinding
|
namespace AIPathfinding
|
||||||
{
|
{
|
||||||
class BattleAction : public ISpecialAction
|
class BattleAction : public SpecialAction
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const int3 targetTile;
|
const int3 targetTile;
|
||||||
@ -25,6 +26,28 @@ namespace AIPathfinding
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const override;
|
virtual void execute(const CGHeroInstance * hero) const override;
|
||||||
|
|
||||||
|
virtual std::string toString() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QuestAction : public SpecialAction
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
QuestInfo questInfo;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QuestAction(QuestInfo questInfo)
|
||||||
|
:questInfo(questInfo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool canAct(const AIPathNode * node) const override;
|
||||||
|
|
||||||
|
virtual Goals::TSubgoal decompose(const CGHeroInstance * hero) const override;
|
||||||
|
|
||||||
|
virtual void execute(const CGHeroInstance * hero) const override;
|
||||||
|
|
||||||
|
virtual std::string toString() const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -10,16 +10,30 @@
|
|||||||
|
|
||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "../../Goals/AdventureSpellCast.h"
|
#include "../../Goals/AdventureSpellCast.h"
|
||||||
|
#include "../../Behaviors/CaptureObjectsBehavior.h"
|
||||||
#include "../../Goals/BuildBoat.h"
|
#include "../../Goals/BuildBoat.h"
|
||||||
#include "../../../../lib/mapping/CMap.h"
|
#include "../../../../lib/mapping/CMap.h"
|
||||||
#include "../../../../lib/mapObjects/MapObjects.h"
|
#include "../../../../lib/mapObjects/MapObjects.h"
|
||||||
#include "BoatActions.h"
|
#include "BoatActions.h"
|
||||||
|
|
||||||
|
extern boost::thread_specific_ptr<CCallback> cb;
|
||||||
|
extern boost::thread_specific_ptr<VCAI> ai;
|
||||||
|
|
||||||
namespace AIPathfinding
|
namespace AIPathfinding
|
||||||
{
|
{
|
||||||
Goals::TSubgoal BuildBoatAction::whatToDo(const CGHeroInstance * hero) const
|
void BuildBoatAction::execute(const CGHeroInstance * hero) const
|
||||||
{
|
{
|
||||||
return Goals::sptr(Goals::BuildBoat(shipyard));
|
return Goals::BuildBoat(shipyard).accept(ai.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
Goals::TSubgoal BuildBoatAction::decompose(const CGHeroInstance * hero) const
|
||||||
|
{
|
||||||
|
if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
||||||
|
{
|
||||||
|
return Goals::sptr(Goals::CaptureObjectsBehavior(shipyard->o));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sptr(Goals::Invalid());
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChainActor * BuildBoatAction::getActor(const ChainActor * sourceActor) const
|
const ChainActor * BuildBoatAction::getActor(const ChainActor * sourceActor) const
|
||||||
@ -27,9 +41,9 @@ namespace AIPathfinding
|
|||||||
return sourceActor->resourceActor;
|
return sourceActor->resourceActor;
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TSubgoal SummonBoatAction::whatToDo(const CGHeroInstance * hero) const
|
void SummonBoatAction::execute(const CGHeroInstance * hero) const
|
||||||
{
|
{
|
||||||
return Goals::sptr(Goals::AdventureSpellCast(hero, SpellID::SUMMON_BOAT));
|
Goals::AdventureSpellCast(hero, SpellID::SUMMON_BOAT).accept(ai.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChainActor * SummonBoatAction::getActor(const ChainActor * sourceActor) const
|
const ChainActor * SummonBoatAction::getActor(const ChainActor * sourceActor) const
|
||||||
@ -48,8 +62,43 @@ namespace AIPathfinding
|
|||||||
dstMode->theNodeBefore = source.node;
|
dstMode->theNodeBefore = source.node;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SummonBoatAction::isAffordableBy(const CGHeroInstance * hero, const AIPathNode * source) const
|
bool BuildBoatAction::canAct(const AIPathNode * source) const
|
||||||
{
|
{
|
||||||
|
auto hero = source->actor->hero;
|
||||||
|
|
||||||
|
if(cb->getPlayerRelations(hero->tempOwner, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
||||||
|
{
|
||||||
|
#if AI_TRACE_LEVEL > 1
|
||||||
|
logAi->trace("Can not build a boat. Shipyard is enemy.");
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TResources boatCost;
|
||||||
|
|
||||||
|
shipyard->getBoatCost(boatCost);
|
||||||
|
|
||||||
|
if(!cb->getResourceAmount().canAfford(source->actor->armyCost + boatCost))
|
||||||
|
{
|
||||||
|
#if AI_TRACE_LEVEL > 1
|
||||||
|
logAi->trace("Can not build a boat. Not enough resources.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BuildBoatAction::toString() const
|
||||||
|
{
|
||||||
|
return "Build Boat at " + shipyard->o->getObjectName();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SummonBoatAction::canAct(const AIPathNode * source) const
|
||||||
|
{
|
||||||
|
auto hero = source->actor->hero;
|
||||||
|
|
||||||
#ifdef VCMI_TRACE_PATHFINDER
|
#ifdef VCMI_TRACE_PATHFINDER
|
||||||
logAi->trace(
|
logAi->trace(
|
||||||
"Hero %s has %d mana and needed %d and already spent %d",
|
"Hero %s has %d mana and needed %d and already spent %d",
|
||||||
@ -62,6 +111,11 @@ namespace AIPathfinding
|
|||||||
return hero->mana >= source->manaCost + getManaCost(hero);
|
return hero->mana >= source->manaCost + getManaCost(hero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string SummonBoatAction::toString() const
|
||||||
|
{
|
||||||
|
return "Summon Boat";
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t SummonBoatAction::getManaCost(const CGHeroInstance * hero) const
|
uint32_t SummonBoatAction::getManaCost(const CGHeroInstance * hero) const
|
||||||
{
|
{
|
||||||
SpellID summonBoat = SpellID::SUMMON_BOAT;
|
SpellID summonBoat = SpellID::SUMMON_BOAT;
|
||||||
|
@ -10,13 +10,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ISpecialAction.h"
|
#include "SpecialAction.h"
|
||||||
#include "../../../../lib/mapping/CMap.h"
|
#include "../../../../lib/mapping/CMap.h"
|
||||||
#include "../../../../lib/mapObjects/MapObjects.h"
|
#include "../../../../lib/mapObjects/MapObjects.h"
|
||||||
|
|
||||||
namespace AIPathfinding
|
namespace AIPathfinding
|
||||||
{
|
{
|
||||||
class VirtualBoatAction : public ISpecialAction
|
class VirtualBoatAction : public SpecialAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual const ChainActor * getActor(const ChainActor * sourceActor) const = 0;
|
virtual const ChainActor * getActor(const ChainActor * sourceActor) const = 0;
|
||||||
@ -24,8 +24,11 @@ namespace AIPathfinding
|
|||||||
|
|
||||||
class SummonBoatAction : public VirtualBoatAction
|
class SummonBoatAction : public VirtualBoatAction
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
const CGHeroInstance * hero;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const override;
|
virtual void execute(const CGHeroInstance * hero) const override;
|
||||||
|
|
||||||
virtual void applyOnDestination(
|
virtual void applyOnDestination(
|
||||||
const CGHeroInstance * hero,
|
const CGHeroInstance * hero,
|
||||||
@ -34,10 +37,12 @@ namespace AIPathfinding
|
|||||||
AIPathNode * dstMode,
|
AIPathNode * dstMode,
|
||||||
const AIPathNode * srcNode) const override;
|
const AIPathNode * srcNode) const override;
|
||||||
|
|
||||||
bool isAffordableBy(const CGHeroInstance * hero, const AIPathNode * source) const;
|
virtual bool canAct(const AIPathNode * source) const;
|
||||||
|
|
||||||
virtual const ChainActor * getActor(const ChainActor * sourceActor) const override;
|
virtual const ChainActor * getActor(const ChainActor * sourceActor) const override;
|
||||||
|
|
||||||
|
virtual std::string toString() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t getManaCost(const CGHeroInstance * hero) const;
|
uint32_t getManaCost(const CGHeroInstance * hero) const;
|
||||||
};
|
};
|
||||||
@ -53,8 +58,14 @@ namespace AIPathfinding
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const override;
|
virtual bool canAct(const AIPathNode * source) const;
|
||||||
|
|
||||||
|
virtual void execute(const CGHeroInstance * hero) const override;
|
||||||
|
|
||||||
|
virtual Goals::TSubgoal decompose(const CGHeroInstance * hero) const override;
|
||||||
|
|
||||||
virtual const ChainActor * getActor(const ChainActor * sourceActor) const override;
|
virtual const ChainActor * getActor(const ChainActor * sourceActor) const override;
|
||||||
|
|
||||||
|
virtual std::string toString() const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
25
AI/Nullkiller/Pathfinding/Actions/SpecialAction.cpp
Normal file
25
AI/Nullkiller/Pathfinding/Actions/SpecialAction.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* SpecialAction.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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SpecialAction.h"
|
||||||
|
#include "../../VCAI.h"
|
||||||
|
#include "../../Goals/CGoal.h"
|
||||||
|
|
||||||
|
Goals::TSubgoal SpecialAction::decompose(const CGHeroInstance * hero) const
|
||||||
|
{
|
||||||
|
return Goals::sptr(Goals::Invalid());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpecialAction::execute(const CGHeroInstance * hero) const
|
||||||
|
{
|
||||||
|
throw cannotFulfillGoalException("Can not execute " + toString());
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* ISpecialAction.h, part of VCMI engine
|
* SpecialAction.h, part of VCMI engine
|
||||||
*
|
*
|
||||||
* Authors: listed in file AUTHORS in main folder
|
* Authors: listed in file AUTHORS in main folder
|
||||||
*
|
*
|
||||||
@ -15,15 +15,17 @@
|
|||||||
|
|
||||||
struct AIPathNode;
|
struct AIPathNode;
|
||||||
|
|
||||||
class ISpecialAction
|
class SpecialAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual bool canAct(const CGHeroInstance * hero) const
|
virtual bool canAct(const AIPathNode * source) const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const = 0;
|
virtual Goals::TSubgoal decompose(const CGHeroInstance * hero) const;
|
||||||
|
|
||||||
|
virtual void execute(const CGHeroInstance * hero) const;
|
||||||
|
|
||||||
virtual void applyOnDestination(
|
virtual void applyOnDestination(
|
||||||
const CGHeroInstance * hero,
|
const CGHeroInstance * hero,
|
||||||
@ -33,4 +35,6 @@ public:
|
|||||||
const AIPathNode * srcNode) const
|
const AIPathNode * srcNode) const
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual std::string toString() const = 0;
|
||||||
};
|
};
|
@ -16,9 +16,41 @@
|
|||||||
|
|
||||||
using namespace AIPathfinding;
|
using namespace AIPathfinding;
|
||||||
|
|
||||||
Goals::TSubgoal TownPortalAction::whatToDo(const CGHeroInstance * hero) const
|
extern boost::thread_specific_ptr<CCallback> cb;
|
||||||
{
|
extern boost::thread_specific_ptr<VCAI> ai;
|
||||||
const CGTownInstance * targetTown = target; // const pointer is not allowed in settown
|
|
||||||
|
|
||||||
return Goals::sptr(Goals::AdventureSpellCast(hero, SpellID::TOWN_PORTAL).settown(targetTown).settile(targetTown->visitablePos()));
|
void TownPortalAction::execute(const CGHeroInstance * hero) const
|
||||||
}
|
{
|
||||||
|
auto goal = Goals::AdventureSpellCast(hero, SpellID::TOWN_PORTAL);
|
||||||
|
|
||||||
|
goal.town = target;
|
||||||
|
goal.tile = target->visitablePos();
|
||||||
|
|
||||||
|
goal.accept(ai.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TownPortalAction::toString() const
|
||||||
|
{
|
||||||
|
return "Town Portal to " + target->name;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
bool TownPortalAction::canAct(const CGHeroInstance * hero, const AIPathNode * source) const
|
||||||
|
{
|
||||||
|
#ifdef VCMI_TRACE_PATHFINDER
|
||||||
|
logAi->trace(
|
||||||
|
"Hero %s has %d mana and needed %d and already spent %d",
|
||||||
|
hero->name,
|
||||||
|
hero->mana,
|
||||||
|
getManaCost(hero),
|
||||||
|
source->manaCost);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return hero->mana >= source->manaCost + getManaCost(hero);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t TownPortalAction::getManaCost(const CGHeroInstance * hero) const
|
||||||
|
{
|
||||||
|
SpellID summonBoat = SpellID::TOWN_PORTAL;
|
||||||
|
|
||||||
|
return hero->getSpellCost(summonBoat.toSpell());
|
||||||
|
}*/
|
@ -10,14 +10,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ISpecialAction.h"
|
#include "SpecialAction.h"
|
||||||
#include "../../../../lib/mapping/CMap.h"
|
#include "../../../../lib/mapping/CMap.h"
|
||||||
#include "../../../../lib/mapObjects/MapObjects.h"
|
#include "../../../../lib/mapObjects/MapObjects.h"
|
||||||
#include "../../Goals/AdventureSpellCast.h"
|
#include "../../Goals/AdventureSpellCast.h"
|
||||||
|
|
||||||
namespace AIPathfinding
|
namespace AIPathfinding
|
||||||
{
|
{
|
||||||
class TownPortalAction : public ISpecialAction
|
class TownPortalAction : public SpecialAction
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const CGTownInstance * target;
|
const CGTownInstance * target;
|
||||||
@ -28,6 +28,8 @@ namespace AIPathfinding
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const override;
|
virtual void execute(const CGHeroInstance * hero) const override;
|
||||||
|
|
||||||
|
virtual std::string toString() const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -9,7 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "Actors.h"
|
#include "Actors.h"
|
||||||
#include "../Goals/VisitHero.h"
|
|
||||||
#include "../VCAI.h"
|
#include "../VCAI.h"
|
||||||
#include "../AIhelper.h"
|
#include "../AIhelper.h"
|
||||||
#include "../../../CCallback.h"
|
#include "../../../CCallback.h"
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#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 "Actions/ISpecialAction.h"
|
#include "Actions/SpecialAction.h"
|
||||||
|
|
||||||
class HeroActor;
|
class HeroActor;
|
||||||
class VCAI;
|
class VCAI;
|
||||||
@ -102,7 +102,7 @@ private:
|
|||||||
void setupSpecialActors();
|
void setupSpecialActors();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<ISpecialAction> exchangeAction;
|
std::shared_ptr<SpecialAction> exchangeAction;
|
||||||
// chain flags, can be combined meaning hero exchange and so on
|
// chain flags, can be combined meaning hero exchange and so on
|
||||||
|
|
||||||
HeroActor(const CGHeroInstance * hero, uint64_t chainMask, const VCAI * ai);
|
HeroActor(const CGHeroInstance * hero, uint64_t chainMask, const VCAI * ai);
|
||||||
|
@ -101,7 +101,7 @@ namespace AIPathfinding
|
|||||||
const CGHeroInstance * hero = nodeStorage->getHero(source.node);
|
const CGHeroInstance * hero = nodeStorage->getHero(source.node);
|
||||||
|
|
||||||
if(vstd::contains(summonableVirtualBoats, hero)
|
if(vstd::contains(summonableVirtualBoats, hero)
|
||||||
&& summonableVirtualBoats.at(hero)->isAffordableBy(hero, nodeStorage->getAINode(source.node)))
|
&& summonableVirtualBoats.at(hero)->canAct(nodeStorage->getAINode(source.node)))
|
||||||
{
|
{
|
||||||
virtualBoat = summonableVirtualBoats.at(hero);
|
virtualBoat = summonableVirtualBoats.at(hero);
|
||||||
}
|
}
|
||||||
|
@ -14,24 +14,6 @@
|
|||||||
|
|
||||||
namespace AIPathfinding
|
namespace AIPathfinding
|
||||||
{
|
{
|
||||||
class QuestAction : public ISpecialAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QuestAction(QuestInfo questInfo)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool canAct(const CGHeroInstance * hero) const override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const override
|
|
||||||
{
|
|
||||||
return Goals::sptr(Goals::Invalid());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AIMovementAfterDestinationRule::AIMovementAfterDestinationRule(
|
AIMovementAfterDestinationRule::AIMovementAfterDestinationRule(
|
||||||
CPlayerSpecificInfoCallback * cb,
|
CPlayerSpecificInfoCallback * cb,
|
||||||
std::shared_ptr<AINodeStorage> nodeStorage)
|
std::shared_ptr<AINodeStorage> nodeStorage)
|
||||||
@ -218,9 +200,9 @@ namespace AIPathfinding
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto hero = nodeStorage->getHero(source.node);
|
auto hero = nodeStorage->getHero(source.node);
|
||||||
auto danger = nodeStorage->evaluateDanger(destination.coord, hero, true);
|
uint64_t danger = nodeStorage->evaluateDanger(destination.coord, hero, true);
|
||||||
double actualArmyValue = srcNode->actor->armyValue - srcNode->armyLoss;
|
uint64_t actualArmyValue = srcNode->actor->armyValue - srcNode->armyLoss;
|
||||||
double loss = nodeStorage->evaluateArmyLoss(hero, actualArmyValue, danger);
|
uint64_t loss = nodeStorage->evaluateArmyLoss(hero, actualArmyValue, danger);
|
||||||
|
|
||||||
if(loss < actualArmyValue)
|
if(loss < actualArmyValue)
|
||||||
{
|
{
|
||||||
|
@ -36,8 +36,6 @@ const float SAFE_ATTACK_CONSTANT = 1.5;
|
|||||||
boost::thread_specific_ptr<CCallback> cb;
|
boost::thread_specific_ptr<CCallback> cb;
|
||||||
boost::thread_specific_ptr<VCAI> ai;
|
boost::thread_specific_ptr<VCAI> ai;
|
||||||
|
|
||||||
//std::map<int, std::map<int, int> > HeroView::infosCount;
|
|
||||||
|
|
||||||
//helper RAII to manage global ai/cb ptrs
|
//helper RAII to manage global ai/cb ptrs
|
||||||
struct SetGlobalState
|
struct SetGlobalState
|
||||||
{
|
{
|
||||||
@ -365,16 +363,6 @@ void VCAI::objectRemoved(const CGObjectInstance * obj)
|
|||||||
vstd::erase_if_present(visitableObjs, obj);
|
vstd::erase_if_present(visitableObjs, obj);
|
||||||
vstd::erase_if_present(alreadyVisited, obj);
|
vstd::erase_if_present(alreadyVisited, obj);
|
||||||
|
|
||||||
std::function<bool(const Goals::TSubgoal &)> checkRemovalValidity = [&](const Goals::TSubgoal & x) -> bool
|
|
||||||
{
|
|
||||||
if((x->goalType == Goals::VISIT_OBJ) && (x->objid == obj->id.getNum()))
|
|
||||||
return true;
|
|
||||||
else if(x->parent && checkRemovalValidity(x->parent)) //repeat this lambda check recursively on parent goal
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
//TODO: Find better way to handle hero boat removal
|
//TODO: Find better way to handle hero boat removal
|
||||||
if(auto hero = dynamic_cast<const CGHeroInstance *>(obj))
|
if(auto hero = dynamic_cast<const CGHeroInstance *>(obj))
|
||||||
{
|
{
|
||||||
@ -1544,42 +1532,6 @@ void VCAI::buildStructure(const CGTownInstance * t, BuildingID building)
|
|||||||
cb->buildBuilding(t, building); //just do this;
|
cb->buildBuilding(t, building); //just do this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::RecruitHero & g)
|
|
||||||
{
|
|
||||||
const CGTownInstance * t = g.town;
|
|
||||||
|
|
||||||
if(!t) t = findTownWithTavern();
|
|
||||||
|
|
||||||
if(t)
|
|
||||||
{
|
|
||||||
recruitHero(t, true);
|
|
||||||
//TODO try to free way to blocked town
|
|
||||||
//TODO: adventure map tavern or prison?
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw cannotFulfillGoalException("No town to recruit hero!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::BuildThis & g)
|
|
||||||
{
|
|
||||||
auto b = BuildingID(g.bid);
|
|
||||||
auto t = g.town;
|
|
||||||
|
|
||||||
if (t)
|
|
||||||
{
|
|
||||||
if (cb->canBuildStructure(t, b) == EBuildingState::ALLOWED)
|
|
||||||
{
|
|
||||||
logAi->debug("Player %d will build %s in town of %s at %s",
|
|
||||||
playerID, t->town->buildings.at(b)->Name(), t->name, t->pos.toString());
|
|
||||||
cb->buildBuilding(t, b);
|
|
||||||
throw goalFulfilledException(sptr(g));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw cannotFulfillGoalException("Cannot build a given structure!");
|
|
||||||
}
|
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::DigAtTile & g)
|
void VCAI::tryRealize(Goals::DigAtTile & g)
|
||||||
{
|
{
|
||||||
assert(g.hero->visitablePos() == g.tile); //surely we want to crash here?
|
assert(g.hero->visitablePos() == g.tile); //surely we want to crash here?
|
||||||
@ -1638,55 +1590,6 @@ void VCAI::tryRealize(Goals::Trade & g) //trade
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::BuyArmy & g)
|
|
||||||
{
|
|
||||||
auto t = g.town;
|
|
||||||
|
|
||||||
ui64 valueBought = 0;
|
|
||||||
//buy the stacks with largest AI value
|
|
||||||
|
|
||||||
auto upgradeSuccessfull = makePossibleUpgrades(t);
|
|
||||||
|
|
||||||
auto armyToBuy = ah->getArmyAvailableToBuy(t->getUpperArmy(), t);
|
|
||||||
|
|
||||||
if(armyToBuy.empty())
|
|
||||||
{
|
|
||||||
if(upgradeSuccessfull)
|
|
||||||
throw goalFulfilledException(sptr(g));
|
|
||||||
|
|
||||||
throw cannotFulfillGoalException("No creatures to buy.");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; valueBought < g.value && i < armyToBuy.size(); i++)
|
|
||||||
{
|
|
||||||
auto res = cb->getResourceAmount();
|
|
||||||
auto & ci = armyToBuy[i];
|
|
||||||
|
|
||||||
if(g.objid != -1 && ci.creID != g.objid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
vstd::amin(ci.count, res / ci.cre->cost);
|
|
||||||
|
|
||||||
if(ci.count)
|
|
||||||
{
|
|
||||||
cb->recruitCreatures(t, t->getUpperArmy(), ci.creID, ci.count, ci.level);
|
|
||||||
valueBought += ci.count * ci.cre->AIValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!valueBought)
|
|
||||||
{
|
|
||||||
throw cannotFulfillGoalException("No creatures to buy.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(t->visitingHero)
|
|
||||||
{
|
|
||||||
moveHeroToTile(t->visitablePos(), t->visitingHero.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
throw goalFulfilledException(sptr(g)); //we bought as many creatures as we wanted
|
|
||||||
}
|
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::Invalid & g)
|
void VCAI::tryRealize(Goals::Invalid & g)
|
||||||
{
|
{
|
||||||
throw cannotFulfillGoalException("I don't know how to fulfill this!");
|
throw cannotFulfillGoalException("I don't know how to fulfill this!");
|
||||||
|
@ -117,11 +117,8 @@ public:
|
|||||||
virtual ~VCAI();
|
virtual ~VCAI();
|
||||||
|
|
||||||
//TODO: use only smart pointers?
|
//TODO: use only smart pointers?
|
||||||
void tryRealize(Goals::RecruitHero & g);
|
|
||||||
void tryRealize(Goals::BuildThis & g);
|
|
||||||
void tryRealize(Goals::DigAtTile & g);
|
void tryRealize(Goals::DigAtTile & g);
|
||||||
void tryRealize(Goals::Trade & g);
|
void tryRealize(Goals::Trade & g);
|
||||||
void tryRealize(Goals::BuyArmy & g);
|
|
||||||
void tryRealize(Goals::Invalid & g);
|
void tryRealize(Goals::Invalid & g);
|
||||||
void tryRealize(Goals::AbstractGoal & g);
|
void tryRealize(Goals::AbstractGoal & g);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user