1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

Nullkiller: refactoring and stabilization of gather army & clusterization

This commit is contained in:
Andrii Danylchenko 2021-05-16 14:56:35 +03:00 committed by Andrii Danylchenko
parent 1fdf0de75d
commit 35a1167f3d
36 changed files with 260 additions and 1527 deletions

View File

@ -241,7 +241,6 @@ void ObjectClusterizer::clusterize()
continue;
}
bool directlyAccessible = false;
std::set<const CGHeroInstance *> heroesProcessed;
for(auto & path : paths)
@ -292,44 +291,33 @@ void ObjectClusterizer::clusterize()
#if AI_TRACE_LEVEL >= 2
logAi->trace("Path added to cluster %s%s", blocker->getObjectName(), blocker->visitablePos().toString());
#endif
continue;
}
else
{
directlyAccessible = true;
}
}
else
{
directlyAccessible = true;
}
heroesProcessed.insert(path.targetHero);
}
if(directlyAccessible)
{
AIPath & shortestPath = paths.front();
float priority = ai->priorityEvaluator->evaluate(Goals::sptr(Goals::ExecuteHeroChain(shortestPath, obj)));
float priority = ai->priorityEvaluator->evaluate(Goals::sptr(Goals::ExecuteHeroChain(path, obj)));
if(priority < MIN_PRIORITY)
continue;
bool interestingObject = shortestPath.turn() <= 2 || priority > 0.5f;
bool interestingObject = path.turn() <= 2 || priority > 0.5f;
if(interestingObject)
{
nearObjects.addObject(obj, shortestPath, priority);
nearObjects.addObject(obj, path, priority);
}
else
{
farObjects.addObject(obj, shortestPath, priority);
farObjects.addObject(obj, path, priority);
}
#if AI_TRACE_LEVEL >= 2
logAi->trace("Path %s added to %s objects. Turn: %d, priority: %f",
shortestPath.toString(),
path.toString(),
interestingObject ? "near" : "far",
shortestPath.turn(),
path.turn(),
priority);
#endif
}

View File

@ -12,7 +12,7 @@
#include "../VCAI.h"
#include "../Engine/Nullkiller.h"
#include "../AIUtility.h"
#include "../Goals/UnlockCluster.h"
#include "../Markers/UnlockCluster.h"
#include "../Goals/Composition.h"
#include "../Behaviors/CaptureObjectsBehavior.h"

View File

@ -11,6 +11,9 @@
#include "../VCAI.h"
#include "../Engine/Nullkiller.h"
#include "../Goals/ExecuteHeroChain.h"
#include "../Goals/Composition.h"
#include "../Markers/HeroExchange.h"
#include "../Markers/ArmyUpgrade.h"
#include "GatherArmyBehavior.h"
#include "../AIUtility.h"
#include "lib/mapping/CMap.h" //for victory conditions
@ -73,7 +76,6 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
}
auto paths = ai->nullkiller->pathfinder->getPathInfo(pos);
std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;
#if AI_TRACE_LEVEL >= 1
logAi->trace("Found %d paths", paths.size());
@ -87,15 +89,6 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
if(path.containsHero(hero)) continue;
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_TRACE_LEVEL >= 2
@ -104,15 +97,35 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
continue;
}
float armyValue = (float)ai->nullkiller->armyManager->howManyReinforcementsCanGet(hero, path.heroArmy) / hero->getArmyStrength();
if(ai->nullkiller->arePathHeroesLocked(path))
{
#if AI_TRACE_LEVEL >= 2
logAi->trace("Ignore path because of locked hero");
#endif
continue;
}
HeroExchange heroExchange(hero, path);
float armyValue = (float)heroExchange.getReinforcementArmyStrength() / hero->getArmyStrength();
// avoid transferring very small amount of army
if(armyValue < 0.1f)
{
#if AI_TRACE_LEVEL >= 2
logAi->trace("Army value is too small.");
#endif
continue;
}
// avoid trying to move bigger army to the weaker one.
if(armyValue > 0.5f)
if(armyValue > 1)
{
#if AI_TRACE_LEVEL >= 2
logAi->trace("Army value is too large.");
#endif
continue;
}
auto danger = path.getTotalDanger();
@ -131,26 +144,28 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
if(isSafe)
{
auto newWay = std::make_shared<ExecuteHeroChain>(path, hero);
Composition composition;
ExecuteHeroChain exchangePath(path, hero);
newWay->strategicalValue = armyValue;
waysToVisitObj.push_back(newWay);
exchangePath.closestWayRatio = 1;
composition.addNext(heroExchange);
composition.addNext(exchangePath);
auto blockedAction = path.getFirstBlockedAction();
if(blockedAction)
{
#if AI_TRACE_LEVEL >= 2
logAi->trace("Action is blocked. Considering decomposition.");
#endif
composition.addNext(blockedAction->decompose(path.targetHero));
}
tasks.push_back(sptr(composition));
}
}
if(waysToVisitObj.empty())
return tasks;
for(auto way : waysToVisitObj)
{
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
continue;
way->closestWayRatio = 1;
tasks.push_back(sptr(*way));
}
return tasks;
}
@ -184,6 +199,14 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
continue;
}
if(ai->nullkiller->arePathHeroesLocked(path))
{
#if AI_TRACE_LEVEL >= 2
logAi->trace("Ignore path because of locked hero");
#endif
continue;
}
if(path.getFirstBlockedAction())
{
#if AI_TRACE_LEVEL >= 2
@ -224,27 +247,13 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
if(isSafe)
{
auto newWay = std::make_shared<ExecuteHeroChain>(path, upgrader);
ExecuteHeroChain newWay(path, upgrader);
newWay.closestWayRatio = 1;
newWay->strategicalValue = armyValue;
newWay->goldCost = upgrade.upgradeCost[Res::GOLD];
waysToVisitObj.push_back(newWay);
tasks.push_back(sptr(Composition().addNext(ArmyUpgrade(path, upgrader, upgrade)).addNext(newWay)));
}
}
if(waysToVisitObj.empty())
return tasks;
for(auto way : waysToVisitObj)
{
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
continue;
way->closestWayRatio = 1;
tasks.push_back(sptr(*way));
}
return tasks;
}

View File

@ -24,17 +24,17 @@ set(VCAI_SRCS
Goals/BuildBoat.cpp
Goals/BuildThis.cpp
Goals/DismissHero.cpp
Goals/GatherTroops.cpp
Goals/BuyArmy.cpp
Goals/AdventureSpellCast.cpp
Goals/CollectRes.cpp
Goals/Trade.cpp
Goals/RecruitHero.cpp
Goals/UnlockCluster.cpp
Goals/DigAtTile.cpp
Goals/GetArtOfType.cpp
Goals/ExecuteHeroChain.cpp
Goals/ExchangeSwapTownHeroes.cpp
Goals/CompleteQuest.cpp
Markers/ArmyUpgrade.cpp
Markers/HeroExchange.cpp
Markers/UnlockCluster.cpp
Engine/Nullkiller.cpp
Engine/PriorityEvaluator.cpp
Analyzers/DangerHitMapAnalyzer.cpp
@ -47,7 +47,6 @@ set(VCAI_SRCS
Behaviors/StartupBehavior.cpp
Behaviors/BuildingBehavior.cpp
Behaviors/GatherArmyBehavior.cpp
Behaviors/CompleteQuestBehavior.cpp
Behaviors/ClusterBehavior.cpp
main.cpp
VCAI.cpp
@ -81,18 +80,18 @@ set(VCAI_HEADERS
Goals/BuildBoat.h
Goals/BuildThis.h
Goals/DismissHero.h
Goals/GatherTroops.h
Goals/BuyArmy.h
Goals/AdventureSpellCast.h
Goals/CollectRes.h
Goals/Trade.h
Goals/UnlockCluster.h
Goals/RecruitHero.h
Goals/DigAtTile.h
Goals/GetArtOfType.h
Goals/ExecuteHeroChain.h
Goals/ExchangeSwapTownHeroes.h
Goals/CompleteQuest.h
Goals/Goals.h
Markers/ArmyUpgrade.h
Markers/HeroExchange.h
Markers/UnlockCluster.h
Engine/Nullkiller.h
Engine/PriorityEvaluator.h
Analyzers/DangerHitMapAnalyzer.h
@ -105,7 +104,6 @@ set(VCAI_HEADERS
Behaviors/StartupBehavior.h
Behaviors/BuildingBehavior.h
Behaviors/GatherArmyBehavior.h
Behaviors/CompleteQuestBehavior.h
Behaviors/ClusterBehavior.h
VCAI.h
)

View File

@ -20,8 +20,10 @@
#include "../../../CCallback.h"
#include "../../../lib/filesystem/Filesystem.h"
#include "../Goals/ExecuteHeroChain.h"
#include "../Goals/UnlockCluster.h"
#include "../Markers/UnlockCluster.h"
#include "../Goals/BuildThis.h"
#include "../Markers/HeroExchange.h"
#include "../Markers/ArmyUpgrade.h"
#define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter
#define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
@ -456,6 +458,38 @@ int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CG
}
}
class HeroExchangeEvaluator : public IEvaluationContextBuilder
{
public:
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal task) const override
{
if(task->goalType != Goals::HERO_EXCHANGE)
return;
Goals::HeroExchange & heroExchange = dynamic_cast<Goals::HeroExchange &>(*task);
uint64_t armyStrength = heroExchange.getReinforcementArmyStrength();
evaluationContext.strategicalValue += 0.5f * armyStrength / heroExchange.hero.get()->getArmyStrength();
}
};
class ArmyUpgradeEvaluator : public IEvaluationContextBuilder
{
public:
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal task) const override
{
if(task->goalType != Goals::ARMY_UPGRADE)
return;
Goals::ArmyUpgrade & armyUpgrade = dynamic_cast<Goals::ArmyUpgrade &>(*task);
uint64_t upgradeValue = armyUpgrade.getUpgradeValue();
evaluationContext.armyReward += upgradeValue;
}
};
class ExecuteHeroChainEvaluationContextBuilder : public IEvaluationContextBuilder
{
public:
@ -610,6 +644,7 @@ PriorityEvaluator::PriorityEvaluator(const Nullkiller * ai)
evaluationContextBuilders.push_back(std::make_shared<ExecuteHeroChainEvaluationContextBuilder>());
evaluationContextBuilders.push_back(std::make_shared<BuildThisEvaluationContextBuilder>());
evaluationContextBuilders.push_back(std::make_shared<ClusterEvaluationContextBuilder>());
evaluationContextBuilders.push_back(std::make_shared<HeroExchangeEvaluator>());
}
EvaluationContext PriorityEvaluator::buildEvaluationContext(Goals::TSubgoal goal) const
@ -628,7 +663,6 @@ EvaluationContext PriorityEvaluator::buildEvaluationContext(Goals::TSubgoal goal
for(auto subgoal : parts)
{
context.strategicalValue += subgoal->strategicalValue;
context.goldCost += subgoal->goldCost;
for(auto builder : evaluationContextBuilders)

View File

@ -63,7 +63,9 @@ namespace Goals
DISMISS_HERO,
COMPOSITION,
CLUSTER_BEHAVIOR,
UNLOCK_CLUSTER
UNLOCK_CLUSTER,
HERO_EXCHANGE,
ARMY_UPGRADE
};
class DLL_EXPORT TSubgoal : public std::shared_ptr<AbstractGoal>
@ -96,7 +98,6 @@ namespace Goals
public:
bool isAbstract; VSETTER(bool, isAbstract)
int value; VSETTER(int, value)
float strategicalValue; VSETTER(float, strategicalValue)
ui64 goldCost; VSETTER(ui64, goldCost)
int resID; VSETTER(int, resID)
int objid; VSETTER(int, objid)
@ -119,7 +120,6 @@ namespace Goals
tile = int3(-1, -1, -1);
town = nullptr;
bid = -1;
strategicalValue = 0;
goldCost = 0;
}
virtual ~AbstractGoal() {}

View File

@ -1,85 +0,0 @@
/*
* ClearWayTo.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 "ClearWayTo.h"
#include "Explore.h"
#include "RecruitHero.h"
#include "../VCAI.h"
#include "../AIUtility.h"
#include "../FuzzyHelper.h"
#include "../AIhelper.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool ClearWayTo::operator==(const ClearWayTo & other) const
{
return other.hero.h == hero.h && other.tile == tile;
}
TSubgoal ClearWayTo::whatToDoToAchieve()
{
assert(cb->isInTheMap(tile)); //set tile
if(!cb->isVisible(tile))
{
logAi->error("Clear way should be used with visible tiles!");
return sptr(Explore());
}
return (fh->chooseSolution(getAllPossibleSubgoals()));
}
bool ClearWayTo::fulfillsMe(TSubgoal goal)
{
if (goal->goalType == VISIT_TILE)
{
if (!hero || hero == goal->hero)
return tile == goal->tile;
}
return false;
}
TGoalVec ClearWayTo::getAllPossibleSubgoals()
{
TGoalVec ret;
std::vector<const CGHeroInstance *> heroes;
if(hero)
heroes.push_back(hero.h);
else
heroes = cb->getHeroesInfo();
for(auto h : heroes)
{
//TODO: handle clearing way to allied heroes that are blocked
//if ((hero && hero->visitablePos() == tile && hero == *h) || //we can't free the way ourselves
// h->visitablePos() == tile) //we are already on that tile! what does it mean?
// continue;
//if our hero is trapped, make sure we request clearing the way from OUR perspective
vstd::concatenate(ret, ai->ah->howToVisitTile(h, tile));
}
if(ret.empty() && ai->canRecruitAnyHero())
ret.push_back(sptr(RecruitHero()));
if(ret.empty())
{
logAi->warn("There is no known way to clear the way to tile %s", tile.toString());
throw goalFulfilledException(sptr(ClearWayTo(tile))); //make sure asigned hero gets unlocked
}
return ret;
}

View File

@ -1,45 +0,0 @@
/*
* ClearWayTo.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"
struct HeroPtr;
class VCAI;
class FuzzyHelper;
namespace Goals
{
class DLL_EXPORT ClearWayTo : public CGoal<ClearWayTo>
{
public:
ClearWayTo()
: CGoal(Goals::CLEAR_WAY_TO)
{
}
ClearWayTo(int3 Tile)
: CGoal(Goals::CLEAR_WAY_TO)
{
tile = Tile;
priority = 5;
}
ClearWayTo(int3 Tile, HeroPtr h)
: CGoal(Goals::CLEAR_WAY_TO)
{
tile = Tile;
hero = h;
priority = 5;
}
TGoalVec getAllPossibleSubgoals() override;
TSubgoal whatToDoToAchieve() override;
bool fulfillsMe(TSubgoal goal) override;
virtual bool operator==(const ClearWayTo & other) const override;
};
}

View File

@ -1,191 +0,0 @@
/*
* CollectRes.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Goals.h"
#include "../VCAI.h"
#include "../AIUtility.h"
#include "../../../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;
using namespace Goals;
bool CollectRes::operator==(const CollectRes & other) const
{
return resID == other.resID;
}
//TGoalVec CollectRes::getAllPossibleSubgoals()
//{
// TGoalVec ret;
//
//auto givesResource = [this](const CGObjectInstance * obj) -> bool
//{
// //TODO: move this logic to object side
// //TODO: remember mithril exists
// //TODO: water objects
// //TODO: Creature banks
// //return false first from once-visitable, before checking if they were even visited
// switch (obj->ID.num)
// {
// case Obj::TREASURE_CHEST:
// return resID == Res::GOLD;
// break;
// case Obj::RESOURCE:
// return obj->subID == resID;
// break;
// case Obj::MINE:
// return (obj->subID == resID &&
// (cb->getPlayerRelations(obj->tempOwner, ai->playerID) == PlayerRelations::ENEMIES)); //don't capture our mines
// break;
// case Obj::CAMPFIRE:
// return true; //contains all resources
// break;
// case Obj::WINDMILL:
// switch (resID)
// {
// case Res::GOLD:
// case Res::WOOD:
// return false;
// }
// break;
// case Obj::WATER_WHEEL:
// if (resID != Res::GOLD)
// return false;
// break;
// case Obj::MYSTICAL_GARDEN:
// if ((resID != Res::GOLD) && (resID != Res::GEMS))
// return false;
// break;
// case Obj::LEAN_TO:
// case Obj::WAGON:
// if (resID != Res::GOLD)
// return false;
// break;
// default:
// return false;
// break;
// }
// return !vstd::contains(ai->alreadyVisited, obj); //for weekly / once visitable
//};
//std::vector<const CGObjectInstance *> objs;
//for (auto obj : ai->visitableObjs)
//{
// if (givesResource(obj))
// objs.push_back(obj);
//}
//for (auto h : cb->getHeroesInfo())
//{
// std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects
// for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
// {
// if (givesResource(obj))
// ourObjs.push_back(obj);
// }
// for (auto obj : ourObjs)
// {
// auto waysToGo = ai->ah->howToVisitObj(h, ObjectIdRef(obj));
// vstd::concatenate(ret, waysToGo);
// }
//}
// return ret;
//}
//TSubgoal CollectRes::whatToDoToAchieve()
//{
// auto goals = getAllPossibleSubgoals();
// auto trade = whatToDoToTrade();
// if (!trade->invalid())
// goals.push_back(trade);
//
// return sptr(Invalid()); //we can always do that
//}
TSubgoal CollectRes::whatToDoToTrade()
{
//std::vector<const IMarket *> markets;
//std::vector<const CGObjectInstance *> visObjs;
//ai->retrieveVisitableObjs(visObjs, true);
//for (const CGObjectInstance * obj : visObjs)
//{
// if (const IMarket * m = IMarket::castFrom(obj, false))
// {
// if (obj->ID == Obj::TOWN && obj->tempOwner == ai->playerID && m->allowsTrade(EMarketMode::RESOURCE_RESOURCE))
// markets.push_back(m);
// else if (obj->ID == Obj::TRADING_POST)
// markets.push_back(m);
// }
//}
//boost::sort(markets, [](const IMarket * m1, const IMarket * m2) -> bool
//{
// return m1->getMarketEfficiency() < m2->getMarketEfficiency();
//});
//markets.erase(boost::remove_if(markets, [](const IMarket * market) -> bool
//{
// if (!(market->o->ID == Obj::TOWN && market->o->tempOwner == ai->playerID))
// {
// if (!ai->isAccessible(market->o->visitablePos()))
// return true;
// }
// return false;
//}), markets.end());
//if (!markets.size())
//{
// for (const CGTownInstance * t : cb->getTownsInfo())
// {
// if (cb->canBuildStructure(t, BuildingID::MARKETPLACE) == EBuildingState::ALLOWED)
// return sptr(BuildThis(BuildingID::MARKETPLACE, t).setpriority(2));
// }
//}
//else
//{
// const IMarket * m = markets.back();
// //attempt trade at back (best prices)
// int howManyCanWeBuy = 0;
// for (Res::ERes i = Res::WOOD; i <= Res::GOLD; vstd::advance(i, 1))
// {
// if (i == resID)
// continue;
// int toGive = -1, toReceive = -1;
// m->getOffer(i, resID, toGive, toReceive, EMarketMode::RESOURCE_RESOURCE);
// assert(toGive > 0 && toReceive > 0);
// howManyCanWeBuy += toReceive * (ai->ah->freeResources()[i] / toGive);
// }
// if (howManyCanWeBuy >= value)
// {
// auto backObj = cb->getTopObj(m->o->visitablePos()); //it'll be a hero if we have one there; otherwise marketplace
// assert(backObj);
// auto objid = m->o->id.getNum();
// if (backObj->tempOwner != ai->playerID) //top object not owned
// {
// return sptr(VisitObj(objid)); //just go there
// }
// else //either it's our town, or we have hero there
// {
// return sptr(Trade(resID, value, objid).setisElementar(true)); //we can do this immediately
// }
// }
//}
return sptr(Invalid()); //cannot trade
}

View File

@ -1,38 +0,0 @@
/*
* CollectRes.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"
struct HeroPtr;
class VCAI;
class FuzzyHelper;
namespace Goals
{
class DLL_EXPORT CollectRes : public CGoal<CollectRes>
{
public:
CollectRes()
: CGoal(Goals::COLLECT_RES)
{
}
CollectRes(int rid, int val)
: CGoal(Goals::COLLECT_RES)
{
resID = rid;
value = val;
}
/*TGoalVec getAllPossibleSubgoals() override;
TSubgoal whatToDoToAchieve() override;*/
TSubgoal whatToDoToTrade();
virtual bool operator==(const CollectRes & other) const override;
};
}

View File

@ -8,8 +8,8 @@
*
*/
#include "StdInc.h"
#include "CompleteQuestBehavior.h"
#include "CaptureObjectsBehavior.h"
#include "CompleteQuest.h"
#include "../Behaviors/CaptureObjectsBehavior.h"
#include "../VCAI.h"
#include "../../../lib/mapping/CMap.h" //for victory conditions
#include "../../../lib/CPathfinder.h"
@ -26,23 +26,6 @@ std::string CompleteQuest::toString() const
TGoalVec CompleteQuest::decompose() const
{
/*TGoalVec solutions;
auto quests = cb->getMyQuests();
for(auto & q : quests)
{
if(q.quest->missionType == CQuest::MISSION_NONE
|| q.quest->progress == CQuest::COMPLETE)
{
continue;
}
vstd::concatenate(solutions, getQuestTasks());
}
return solutions;*/
if(q.obj && (q.obj->ID == Obj::BORDER_GATE || q.obj->ID == Obj::BORDERGUARD))
{
return missionKeymaster();

View File

@ -1,90 +0,0 @@
/*
* Conquer.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Goals.h"
#include "../VCAI.h"
#include "../AIUtility.h"
#include "../AIhelper.h"
#include "../FuzzyHelper.h"
#include "../ResourceManager.h"
#include "../BuildingManager.h"
#include "../../../lib/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 Conquer::operator==(const Conquer & other) const
{
return other.hero.h == hero.h;
}
TSubgoal Conquer::whatToDoToAchieve()
{
logAi->trace("Entering goal CONQUER");
return fh->chooseSolution(getAllPossibleSubgoals());
}
TGoalVec Conquer::getAllPossibleSubgoals()
{
TGoalVec ret;
auto conquerable = [](const CGObjectInstance * obj) -> bool
{
if(cb->getPlayerRelations(ai->playerID, obj->tempOwner) == PlayerRelations::ENEMIES)
{
switch(obj->ID.num)
{
case Obj::TOWN:
case Obj::HERO:
case Obj::CREATURE_GENERATOR1:
case Obj::MINE: //TODO: check ai->knownSubterraneanGates
return true;
}
}
return false;
};
std::vector<const CGObjectInstance *> objs;
for(auto obj : ai->visitableObjs)
{
if(conquerable(obj))
objs.push_back(obj);
}
for(auto h : cb->getHeroesInfo())
{
std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects
for(auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
{
if(conquerable(obj))
ourObjs.push_back(obj);
}
for(auto obj : ourObjs)
{
auto waysToGo = ai->ah->howToVisitObj(h, ObjectIdRef(obj));
vstd::concatenate(ret, waysToGo);
}
}
if(!objs.empty() && ai->canRecruitAnyHero()) //probably no point to recruit hero if we see no objects to capture
ret.push_back(sptr(RecruitHero()));
if(ret.empty())
ret.push_back(sptr(Explore())); //we need to find an enemy
return ret;
}

View File

@ -1,32 +0,0 @@
/*
* Conquer.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"
struct HeroPtr;
class VCAI;
class FuzzyHelper;
namespace Goals
{
class DLL_EXPORT Conquer : public CGoal<Conquer>
{
public:
Conquer()
: CGoal(Goals::CONQUER)
{
priority = 10;
}
TGoalVec getAllPossibleSubgoals() override;
TSubgoal whatToDoToAchieve() override;
virtual bool operator==(const Conquer & other) const override;
};
}

View File

@ -1,432 +0,0 @@
/*
* Explore.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Goals.h"
#include "../VCAI.h"
#include "../AIUtility.h"
#include "../AIhelper.h"
#include "../FuzzyHelper.h"
#include "../ResourceManager.h"
#include "../BuildingManager.h"
#include "../../../lib/mapping/CMap.h" //for victory conditions
#include "../../../lib/CPathfinder.h"
#include "../../../lib/StringConstants.h"
#include "../../../lib/CPlayerState.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
namespace Goals
{
struct ExplorationHelper
{
HeroPtr hero;
int sightRadius;
float bestValue;
TSubgoal bestGoal;
VCAI * aip;
CCallback * cbp;
const TeamState * ts;
int3 ourPos;
bool allowDeadEndCancellation;
bool allowGatherArmy;
ExplorationHelper(HeroPtr h, bool gatherArmy)
{
cbp = cb.get();
aip = ai.get();
hero = h;
ts = cbp->getPlayerTeam(ai->playerID);
sightRadius = hero->getSightRadius();
bestGoal = sptr(Goals::Invalid());
bestValue = 0;
ourPos = h->convertPosition(h->pos, false);
allowDeadEndCancellation = true;
allowGatherArmy = gatherArmy;
}
void scanSector(int scanRadius)
{
for(int x = ourPos.x - scanRadius; x <= ourPos.x + scanRadius; x++)
{
for(int y = ourPos.y - scanRadius; y <= ourPos.y + scanRadius; y++)
{
int3 tile = int3(x, y, ourPos.z);
if(cbp->isInTheMap(tile) && ts->fogOfWarMap[tile.x][tile.y][tile.z])
{
scanTile(tile);
}
}
}
}
void scanMap()
{
int3 mapSize = cbp->getMapSize();
int perimeter = 2 * sightRadius * (mapSize.x + mapSize.y);
std::vector<int3> from;
std::vector<int3> to;
from.reserve(perimeter);
to.reserve(perimeter);
foreach_tile_pos([&](const int3 & pos)
{
if(ts->fogOfWarMap[pos.x][pos.y][pos.z])
{
bool hasInvisibleNeighbor = false;
foreach_neighbour(cbp, pos, [&](CCallback * cbp, int3 neighbour)
{
if(!ts->fogOfWarMap[neighbour.x][neighbour.y][neighbour.z])
{
hasInvisibleNeighbor = true;
}
});
if(hasInvisibleNeighbor)
from.push_back(pos);
}
});
logAi->debug("Exploration scan visible area perimeter for hero %s", hero.name);
for(const int3 & tile : from)
{
scanTile(tile);
}
if(!bestGoal->invalid())
{
return;
}
allowDeadEndCancellation = false;
for(int i = 0; i < sightRadius; i++)
{
getVisibleNeighbours(from, to);
vstd::concatenate(from, to);
vstd::removeDuplicates(from);
}
logAi->debug("Exploration scan all possible tiles for hero %s", hero.name);
for(const int3 & tile : from)
{
scanTile(tile);
}
}
void scanTile(const int3 & tile)
{
if(tile == ourPos
|| !aip->ah->isTileAccessible(hero, tile)) //shouldn't happen, but it does
return;
int tilesDiscovered = howManyTilesWillBeDiscovered(tile);
if(!tilesDiscovered)
return;
auto waysToVisit = aip->ah->howToVisitTile(hero, tile, allowGatherArmy);
for(auto goal : waysToVisit)
{
if(goal->evaluationContext.movementCost <= 0.0) // should not happen
continue;
float ourValue = (float)tilesDiscovered * tilesDiscovered / goal->evaluationContext.movementCost;
if(ourValue > bestValue) //avoid costly checks of tiles that don't reveal much
{
auto obj = cb->getTopObj(tile);
// picking up resources does not yield any exploration at all.
// if it blocks the way to some explorable tile AIPathfinder will take care of it
if(obj && obj->blockVisit)
{
continue;
}
if(isSafeToVisit(hero, tile))
{
bestGoal = goal;
bestValue = ourValue;
}
}
}
}
void getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out) const
{
for(const int3 & tile : tiles)
{
foreach_neighbour(cbp, tile, [&](CCallback * cbp, int3 neighbour)
{
if(ts->fogOfWarMap[neighbour.x][neighbour.y][neighbour.z])
{
out.push_back(neighbour);
}
});
}
}
int howManyTilesWillBeDiscovered(
const int3 & pos) const
{
int ret = 0;
for(int x = pos.x - sightRadius; x <= pos.x + sightRadius; x++)
{
for(int y = pos.y - sightRadius; y <= pos.y + sightRadius; y++)
{
int3 npos = int3(x, y, pos.z);
if(cbp->isInTheMap(npos)
&& pos.dist2d(npos) - 0.5 < sightRadius
&& !ts->fogOfWarMap[npos.x][npos.y][npos.z])
{
if(allowDeadEndCancellation
&& !hasReachableNeighbor(npos))
{
continue;
}
ret++;
}
}
}
return ret;
}
bool hasReachableNeighbor(const int3 &pos) const
{
for(crint3 dir : int3::getDirs())
{
int3 tile = pos + dir;
if(cbp->isInTheMap(tile))
{
auto isAccessible = aip->ah->isTileAccessible(hero, tile);
if(isAccessible)
return true;
}
}
return false;
}
};
}
bool Explore::operator==(const Explore & other) const
{
return other.hero.h == hero.h && other.allowGatherArmy == allowGatherArmy;
}
TSubgoal Explore::whatToDoToAchieve()
{
return sptr(Goals::Invalid());
}
TGoalVec Explore::getAllPossibleSubgoals()
{
TGoalVec ret;
std::vector<const CGHeroInstance *> heroes;
if(hero)
{
heroes.push_back(hero.h);
}
else
{
//heroes = ai->getUnblockedHeroes();
heroes = cb->getHeroesInfo();
vstd::erase_if(heroes, [](const HeroPtr h)
{
if(ai->getGoal(h)->goalType == EXPLORE) //do not reassign hero who is already explorer
return true;
if(!ai->isAbleToExplore(h))
return true;
return !h->movement; //saves time, immobile heroes are useless anyway
});
}
//try to use buildings that uncover map
std::vector<const CGObjectInstance *> objs;
for(auto obj : ai->visitableObjs)
{
if(!vstd::contains(ai->alreadyVisited, obj))
{
switch(obj->ID.num)
{
case Obj::REDWOOD_OBSERVATORY:
case Obj::PILLAR_OF_FIRE:
case Obj::CARTOGRAPHER:
objs.push_back(obj);
break;
case Obj::MONOLITH_ONE_WAY_ENTRANCE:
case Obj::MONOLITH_TWO_WAY:
case Obj::SUBTERRANEAN_GATE:
auto tObj = dynamic_cast<const CGTeleport *>(obj);
assert(ai->knownTeleportChannels.find(tObj->channel) != ai->knownTeleportChannels.end());
if(TeleportChannel::IMPASSABLE != ai->knownTeleportChannels[tObj->channel]->passability)
objs.push_back(obj);
break;
}
}
else
{
switch(obj->ID.num)
{
case Obj::MONOLITH_TWO_WAY:
case Obj::SUBTERRANEAN_GATE:
auto tObj = dynamic_cast<const CGTeleport *>(obj);
if(TeleportChannel::IMPASSABLE == ai->knownTeleportChannels[tObj->channel]->passability)
break;
for(auto exit : ai->knownTeleportChannels[tObj->channel]->exits)
{
if(!cb->getObj(exit))
{ // Always attempt to visit two-way teleports if one of channel exits is not visible
objs.push_back(obj);
break;
}
}
break;
}
}
}
for(auto h : heroes)
{
for(auto obj : objs) //double loop, performance risk?
{
auto waysToVisitObj = ai->ah->howToVisitObj(h, obj, allowGatherArmy);
vstd::concatenate(ret, waysToVisitObj);
}
TSubgoal goal = exploreNearestNeighbour(h);
if(!goal->invalid())
{
ret.push_back(goal);
}
}
if(ret.empty())
{
for(auto h : heroes)
{
logAi->trace("Exploration searching for a new point for hero %s", h->name);
TSubgoal goal = explorationNewPoint(h);
if(goal->invalid())
{
ai->markHeroUnableToExplore(h); //there is no freely accessible tile, do not poll this hero anymore
}
else
{
ret.push_back(goal);
}
}
}
//we either don't have hero yet or none of heroes can explore
if((!hero || ret.empty()) && ai->canRecruitAnyHero())
ret.push_back(sptr(RecruitHero()));
if(ret.empty())
{
throw goalFulfilledException(sptr(Explore().sethero(hero)));
}
return ret;
}
TSubgoal Explore::explorationBestNeighbour(int3 hpos, HeroPtr h) const
{
ExplorationHelper scanResult(h, allowGatherArmy);
for(crint3 dir : int3::getDirs())
{
int3 tile = hpos + dir;
if(cb->isInTheMap(tile))
{
scanResult.scanTile(tile);
}
}
return scanResult.bestGoal;
}
TSubgoal Explore::explorationNewPoint(HeroPtr h) const
{
ExplorationHelper scanResult(h, allowGatherArmy);
scanResult.scanSector(10);
if(!scanResult.bestGoal->invalid())
{
return scanResult.bestGoal;
}
scanResult.scanMap();
return scanResult.bestGoal;
}
TSubgoal Explore::exploreNearestNeighbour(HeroPtr h) const
{
TimeCheck tc("where to explore");
int3 hpos = h->visitablePos();
//look for nearby objs -> visit them if they're close enough
const int DIST_LIMIT = 3;
const float COST_LIMIT = .2; //todo: fine tune
std::vector<const CGObjectInstance *> nearbyVisitableObjs;
for(int x = hpos.x - DIST_LIMIT; x <= hpos.x + DIST_LIMIT; ++x) //get only local objects instead of all possible objects on the map
{
for(int y = hpos.y - DIST_LIMIT; y <= hpos.y + DIST_LIMIT; ++y)
{
for(auto obj : cb->getVisitableObjs(int3(x, y, hpos.z), false))
{
if(ai->isGoodForVisit(obj, h, COST_LIMIT))
{
nearbyVisitableObjs.push_back(obj);
}
}
}
}
if(nearbyVisitableObjs.size())
{
vstd::removeDuplicates(nearbyVisitableObjs); //one object may occupy multiple tiles
boost::sort(nearbyVisitableObjs, CDistanceSorter(h.get()));
TSubgoal pickupNearestObj = fh->chooseSolution(ai->ah->howToVisitObj(h, nearbyVisitableObjs.back(), false));
if(!pickupNearestObj->invalid())
{
return pickupNearestObj;
}
}
//check if nearby tiles allow us to reveal anything - this is quick
return explorationBestNeighbour(hpos, h);
}

View File

@ -1,64 +0,0 @@
///*
//* Explore.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"
//
//struct HeroPtr;
//class VCAI;
//class FuzzyHelper;
//
//namespace Goals
//{
// struct ExplorationHelper;
//
// class DLL_EXPORT Explore : public CGoal<Explore>
// {
// private:
// bool allowGatherArmy;
//
// public:
// Explore(bool allowGatherArmy)
// : CGoal(Goals::EXPLORE), allowGatherArmy(allowGatherArmy)
// {
// priority = 1;
// }
//
// Explore()
// : Explore(true)
// {
// }
//
// Explore(HeroPtr h)
// : CGoal(Goals::EXPLORE)
// {
// hero = h;
// priority = 1;
// }
// TGoalVec getAllPossibleSubgoals() override;
// TSubgoal whatToDoToAchieve() override;
// virtual bool operator==(const Explore & other) const override;
//
// private:
// TSubgoal exploreNearestNeighbour(HeroPtr h) const;
// TSubgoal explorationNewPoint(HeroPtr h) const;
// TSubgoal explorationBestNeighbour(int3 hpos, HeroPtr h) const;
// void explorationScanTile(const int3 & tile, ExplorationHelper & scanResult) const;
// bool hasReachableNeighbor(const int3 &pos, HeroPtr hero, CCallback * cbp, VCAI * vcai) const;
//
// void getVisibleNeighbours(
// const std::vector<int3> & tiles,
// std::vector<int3> & out,
// CCallback * cbp,
// const TeamState * ts) const;
//
// int howManyTilesWillBeDiscovered(const int3 & pos, ExplorationHelper & scanResult) const;
// };
//}

View File

@ -1,138 +0,0 @@
/*
* GatherTroops.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Goals.h"
#include "../VCAI.h"
#include "../AIUtility.h"
#include "../../../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;
using namespace Goals;
bool GatherTroops::operator==(const GatherTroops & other) const
{
return objid == other.objid;
}
int GatherTroops::getCreaturesCount(const CArmedInstance * army)
{
int count = 0;
for(auto stack : army->Slots())
{
if(objid == stack.second->getCreatureID().num)
{
count += stack.second->count;
}
}
return count;
}
//
//TSubgoal GatherTroops::whatToDoToAchieve()
//{
// logAi->trace("Entering GatherTroops::whatToDoToAchieve");
//
// auto heroes = cb->getHeroesInfo(true);
//
// for(auto hero : heroes)
// {
// if(getCreaturesCount(hero) >= this->value)
// {
// logAi->trace("Completing GATHER_TROOPS by hero %s", hero->name);
//
// throw goalFulfilledException(sptr(*this));
// }
// }
//
// return sptr(Invalid());
//}
//
//TGoalVec GatherTroops::getAllPossibleSubgoals()
//{
// TGoalVec solutions;
//for(const CGTownInstance * t : cb->getTownsInfo())
//{
// int count = getCreaturesCount(t->getUpperArmy());
// if(count >= this->value)
// {
// if(t->visitingHero)
// {
// solutions.push_back(sptr(VisitObj(t->id.getNum()).sethero(t->visitingHero.get())));
// }
// else
// {
// vstd::concatenate(solutions, ai->ah->howToVisitObj(t));
// }
// continue;
// }
// auto creature = VLC->creh->creatures[objid];
// if(t->subID == creature->faction) //TODO: how to force AI to build unupgraded creatures? :O
// {
// auto creatures = vstd::tryAt(t->town->creatures, creature->level - 1);
// if(!creatures)
// continue;
// int upgradeNumber = vstd::find_pos(*creatures, creature->idNumber);
// if(upgradeNumber < 0)
// continue;
// BuildingID bid(BuildingID::DWELL_FIRST + creature->level - 1 + upgradeNumber * GameConstants::CREATURES_PER_TOWN);
// if(t->hasBuilt(bid) && ai->ah->freeResources().canAfford(creature->cost)) //this assumes only creatures with dwellings are assigned to faction
// {
// solutions.push_back(sptr(BuyArmy(t, creature->AIValue * this->value).setobjid(objid)));
// }
// /*else //disable random building requests for now - this code needs to know a lot of town/resource context to do more good than harm
// {
// return sptr(BuildThis(bid, t).setpriority(priority));
// }*/
// }
//}
//for(auto obj : ai->visitableObjs)
//{
// auto d = dynamic_cast<const CGDwelling *>(obj);
// if(!d || obj->ID == Obj::TOWN)
// continue;
// for(auto creature : d->creatures)
// {
// if(creature.first) //there are more than 0 creatures avaliabe
// {
// for(auto type : creature.second)
// {
// if(type == objid && ai->ah->freeResources().canAfford(VLC->creh->creatures[type]->cost))
// vstd::concatenate(solutions, ai->ah->howToVisitObj(obj));
// }
// }
// }
//}
//CreatureID creID = CreatureID(objid);
//vstd::erase_if(solutions, [&](TSubgoal goal)->bool
//{
// return goal->hero && !goal->hero->getSlotFor(creID).validSlot() && !goal->hero->getFreeSlot().validSlot();
//});
// return solutions;
// //TODO: exchange troops between heroes
//}

View File

@ -1,38 +0,0 @@
/*
* GatherTroops.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"
struct HeroPtr;
class VCAI;
class FuzzyHelper;
namespace Goals
{
class DLL_EXPORT GatherTroops : public CGoal<GatherTroops>
{
public:
GatherTroops()
: CGoal(Goals::GATHER_TROOPS)
{
}
GatherTroops(int type, int val)
: CGoal(Goals::GATHER_TROOPS)
{
objid = type;
value = val;
}
virtual bool operator==(const GatherTroops & other) const override;
private:
int getCreaturesCount(const CArmedInstance * army);
};
}

View File

@ -1,29 +0,0 @@
/*
* GetArtOfType.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 "GetArtOfType.h"
#include "../VCAI.h"
#include "../AIUtility.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
using namespace Goals;
bool GetArtOfType::operator==(const GetArtOfType & other) const
{
return other.hero.h == hero.h && other.objid == objid;
}
//
//TSubgoal GetArtOfType::whatToDoToAchieve()
//{
// return sptr(FindObj(Obj::ARTIFACT, aid));
//}

View File

@ -1,34 +0,0 @@
/*
* GetArtOfType.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"
struct HeroPtr;
class VCAI;
class FuzzyHelper;
namespace Goals
{
class DLL_EXPORT GetArtOfType : public CGoal<GetArtOfType>
{
public:
GetArtOfType()
: CGoal(Goals::GET_ART_TYPE)
{
}
GetArtOfType(int type)
: CGoal(Goals::GET_ART_TYPE)
{
aid = type;
}
virtual bool operator==(const GetArtOfType & other) const override;
};
}

View File

@ -14,10 +14,7 @@
#include "BuildBoat.h"
#include "BuildThis.h"
#include "BuyArmy.h"
#include "GatherTroops.h"
#include "Trade.h"
#include "CollectRes.h"
#include "RecruitHero.h"
#include "GetArtOfType.h"
#include "DigAtTile.h"
#include "AdventureSpellCast.h"

View File

@ -1,29 +0,0 @@
/*
* VisitHero.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 "VisitHero.h"
#include "Invalid.h"
#include "../VCAI.h"
#include "../AIUtility.h"
#include "../AIhelper.h"
#include "../FuzzyHelper.h"
#include "../../../lib/mapping/CMap.h" //for victory conditions
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool VisitHero::operator==(const VisitHero & other) const
{
return other.hero.h == hero.h && other.objid == objid;
}

View File

@ -1,36 +0,0 @@
/*
* VisitHero.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
#error not used
#include "CGoal.h"
struct HeroPtr;
class VCAI;
class FuzzyHelper;
namespace Goals
{
class DLL_EXPORT VisitHero : public CGoal<VisitHero>
{
public:
VisitHero()
: CGoal(Goals::VISIT_HERO)
{
}
VisitHero(int hid)
: CGoal(Goals::VISIT_HERO)
{
objid = hid;
}
virtual bool operator==(const VisitHero & other) const override;
};
}

View File

@ -1,41 +0,0 @@
/*
* VisitObj.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Goals.h"
#include "../VCAI.h"
#include "../AIUtility.h"
#include "../AIhelper.h"
#include "../FuzzyHelper.h"
#include "../../../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 VisitObj::operator==(const VisitObj & other) const
{
return other.hero.h == hero.h && other.objid == objid;
}
VisitObj::VisitObj(int Objid)
: CGoal(VISIT_OBJ)
{
objid = Objid;
auto obj = ai->myCb->getObjInstance(ObjectInstanceID(objid));
if(obj)
tile = obj->visitablePos();
else
logAi->error("VisitObj constructed with invalid object instance %d", Objid);
}

View File

@ -1,30 +0,0 @@
/*
* VisitObj.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
#error not used
#include "CGoal.h"
struct HeroPtr;
class VCAI;
class FuzzyHelper;
namespace Goals
{
class DLL_EXPORT VisitObj : public CGoal<VisitObj> //this goal was previously known as GetObj
{
public:
VisitObj() = delete; // empty constructor not allowed
VisitObj(int Objid);
virtual bool operator==(const VisitObj & other) const override;
};
}

View File

@ -1,30 +0,0 @@
/*
* VisitTile.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "Goals.h"
#include "../VCAI.h"
#include "../AIUtility.h"
#include "../AIhelper.h"
#include "../FuzzyHelper.h"
#include "../../../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 VisitTile::operator==(const VisitTile & other) const
{
return other.hero.h == hero.h && other.tile == tile;
}

View File

@ -1,35 +0,0 @@
/*
* VisitTile.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
#error not used
#include "CGoal.h"
struct HeroPtr;
class VCAI;
class FuzzyHelper;
namespace Goals
{
class DLL_EXPORT VisitTile : public CGoal<VisitTile>
//tile, in conjunction with hero elementar; assumes tile is reachable
{
public:
VisitTile() {} // empty constructor not allowed
VisitTile(int3 Tile)
: CGoal(Goals::VISIT_TILE)
{
tile = Tile;
}
virtual bool operator==(const VisitTile & other) const override;
};
}

View File

@ -0,0 +1,36 @@
/*
* ArmyUpgrade.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 "ArmyUpgrade.h"
#include "../VCAI.h"
#include "../Engine/Nullkiller.h"
#include "../AIUtility.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
using namespace Goals;
ArmyUpgrade::ArmyUpgrade(const AIPath & upgradePath, const CGObjectInstance * upgrader, const ArmyUpgradeInfo & upgrade)
: CGoal(Goals::ARMY_UPGRADE), upgrader(upgrader), upgradeValue(upgrade.upgradeValue),
initialValue(upgradePath.heroArmy->getArmyStrength()), goldCost(upgrade.upgradeCost[Res::GOLD])
{
sethero(upgradePath.targetHero);
}
bool ArmyUpgrade::operator==(const ArmyUpgrade & other) const
{
return false;
}
std::string ArmyUpgrade::toString() const
{
return "Army upgrade at " + upgrader->getObjectName() + upgrader->visitablePos().toString();
}

View File

@ -0,0 +1,35 @@
/*
* ArmyUpgrade.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 "../Goals/CGoal.h"
#include "../Pathfinding/AINodeStorage.h"
#include "../Analyzers/ArmyManager.h"
namespace Goals
{
class DLL_EXPORT ArmyUpgrade : public CGoal<ArmyUpgrade>
{
private:
const CGObjectInstance * upgrader;
uint64_t initialValue;
uint64_t upgradeValue;
uint64_t goldCost;
public:
ArmyUpgrade(const AIPath & upgradePath, const CGObjectInstance * upgrader, const ArmyUpgradeInfo & upgrade);
virtual bool operator==(const ArmyUpgrade & other) const override;
virtual std::string toString() const override;
uint64_t getUpgradeValue() const { return upgradeValue; }
uint64_t getInitialArmyValue() const { return initialValue; }
};
}

View File

@ -0,0 +1,36 @@
/*
* HeroExchange.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 "HeroExchange.h"
#include "../VCAI.h"
#include "../Engine/Nullkiller.h"
#include "../AIUtility.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
using namespace Goals;
bool HeroExchange::operator==(const HeroExchange & other) const
{
return false;
}
std::string HeroExchange::toString() const
{
return "Hero exchange " + exchangePath.toString();
}
uint64_t HeroExchange::getReinforcementArmyStrength() const
{
uint64_t armyValue = ai->nullkiller->armyManager->howManyReinforcementsCanGet(hero.get(), exchangePath.heroArmy);
return armyValue;
}

View File

@ -0,0 +1,34 @@
/*
* HeroExchange.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 "../Goals/CGoal.h"
#include "../Pathfinding/AINodeStorage.h"
namespace Goals
{
class DLL_EXPORT HeroExchange : public CGoal<HeroExchange>
{
private:
AIPath exchangePath;
public:
HeroExchange(const CGHeroInstance * targetHero, const AIPath & exchangePath)
: CGoal(Goals::HERO_EXCHANGE), exchangePath(exchangePath)
{
sethero(targetHero);
}
virtual bool operator==(const HeroExchange & other) const override;
virtual std::string toString() const override;
uint64_t getReinforcementArmyStrength() const;
};
}

View File

@ -9,7 +9,7 @@
*/
#pragma once
#include "CGoal.h"
#include "../Goals/CGoal.h"
#include "../Analyzers/ObjectClusterizer.h"

View File

@ -1112,10 +1112,10 @@ AIPath::AIPath()
std::shared_ptr<const SpecialAction> AIPath::getFirstBlockedAction() const
{
for(auto node : nodes)
for(auto node = nodes.rbegin(); node != nodes.rend(); node++)
{
if(node.specialAction && node.actionIsBlocked)
return node.specialAction;
if(node->specialAction && node->actionIsBlocked)
return node->specialAction;
}
return std::shared_ptr<const SpecialAction>();

View File

@ -11,7 +11,7 @@
#pragma once
#define PATHFINDER_TRACE_LEVEL 0
#define AI_TRACE_LEVEL 0
#define AI_TRACE_LEVEL 2
#define SCOUT_TURN_DISTANCE_LIMIT 3
#include "../../../lib/CPathfinder.h"

View File

@ -11,7 +11,7 @@
#include "StdInc.h"
#include "BattleAction.h"
#include "../../VCAI.h"
#include "../../Behaviors/CompleteQuestBehavior.h"
#include "../../Goals/CompleteQuest.h"
#include "../../../../lib/mapping/CMap.h" //for victory conditions
extern boost::thread_specific_ptr<CCallback> cb;