diff --git a/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp b/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp index dfd8cab20..9315932ce 100644 --- a/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp +++ b/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp @@ -241,7 +241,6 @@ void ObjectClusterizer::clusterize() continue; } - bool directlyAccessible = false; std::set 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 } diff --git a/AI/Nullkiller/Behaviors/ClusterBehavior.cpp b/AI/Nullkiller/Behaviors/ClusterBehavior.cpp index 3b0cbdc6a..ef9a80692 100644 --- a/AI/Nullkiller/Behaviors/ClusterBehavior.cpp +++ b/AI/Nullkiller/Behaviors/ClusterBehavior.cpp @@ -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" diff --git a/AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp b/AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp index 3f959fb2d..aa85620f3 100644 --- a/AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp +++ b/AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp @@ -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> 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(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(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; } diff --git a/AI/Nullkiller/CMakeLists.txt b/AI/Nullkiller/CMakeLists.txt index 221dc6656..b93066b60 100644 --- a/AI/Nullkiller/CMakeLists.txt +++ b/AI/Nullkiller/CMakeLists.txt @@ -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 ) diff --git a/AI/Nullkiller/Engine/PriorityEvaluator.cpp b/AI/Nullkiller/Engine/PriorityEvaluator.cpp index 73a1f18c1..ca74906d3 100644 --- a/AI/Nullkiller/Engine/PriorityEvaluator.cpp +++ b/AI/Nullkiller/Engine/PriorityEvaluator.cpp @@ -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(*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(*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()); evaluationContextBuilders.push_back(std::make_shared()); evaluationContextBuilders.push_back(std::make_shared()); + evaluationContextBuilders.push_back(std::make_shared()); } 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) diff --git a/AI/Nullkiller/Goals/AbstractGoal.h b/AI/Nullkiller/Goals/AbstractGoal.h index 17e95caa7..70b749e61 100644 --- a/AI/Nullkiller/Goals/AbstractGoal.h +++ b/AI/Nullkiller/Goals/AbstractGoal.h @@ -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 @@ -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() {} diff --git a/AI/Nullkiller/Goals/ClearWayTo.cpp b/AI/Nullkiller/Goals/ClearWayTo.cpp deleted file mode 100644 index e20c26ad5..000000000 --- a/AI/Nullkiller/Goals/ClearWayTo.cpp +++ /dev/null @@ -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 cb; -extern boost::thread_specific_ptr 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 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; -} diff --git a/AI/Nullkiller/Goals/ClearWayTo.h b/AI/Nullkiller/Goals/ClearWayTo.h deleted file mode 100644 index 432f1ad79..000000000 --- a/AI/Nullkiller/Goals/ClearWayTo.h +++ /dev/null @@ -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 - { - 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; - }; -} diff --git a/AI/Nullkiller/Goals/CollectRes.cpp b/AI/Nullkiller/Goals/CollectRes.cpp deleted file mode 100644 index 94d048cc1..000000000 --- a/AI/Nullkiller/Goals/CollectRes.cpp +++ /dev/null @@ -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 cb; -extern boost::thread_specific_ptr 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 objs; - //for (auto obj : ai->visitableObjs) - //{ - // if (givesResource(obj)) - // objs.push_back(obj); - //} - //for (auto h : cb->getHeroesInfo()) - //{ - // std::vector 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 markets; - - //std::vector 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 -} diff --git a/AI/Nullkiller/Goals/CollectRes.h b/AI/Nullkiller/Goals/CollectRes.h deleted file mode 100644 index 9bc942b83..000000000 --- a/AI/Nullkiller/Goals/CollectRes.h +++ /dev/null @@ -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 - { - 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; - }; -} diff --git a/AI/Nullkiller/Behaviors/CompleteQuestBehavior.cpp b/AI/Nullkiller/Goals/CompleteQuest.cpp similarity index 93% rename from AI/Nullkiller/Behaviors/CompleteQuestBehavior.cpp rename to AI/Nullkiller/Goals/CompleteQuest.cpp index 0c01bb14f..b652314df 100644 --- a/AI/Nullkiller/Behaviors/CompleteQuestBehavior.cpp +++ b/AI/Nullkiller/Goals/CompleteQuest.cpp @@ -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(); diff --git a/AI/Nullkiller/Behaviors/CompleteQuestBehavior.h b/AI/Nullkiller/Goals/CompleteQuest.h similarity index 100% rename from AI/Nullkiller/Behaviors/CompleteQuestBehavior.h rename to AI/Nullkiller/Goals/CompleteQuest.h diff --git a/AI/Nullkiller/Goals/Conquer.cpp b/AI/Nullkiller/Goals/Conquer.cpp deleted file mode 100644 index 8ac127dc1..000000000 --- a/AI/Nullkiller/Goals/Conquer.cpp +++ /dev/null @@ -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 cb; -extern boost::thread_specific_ptr 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 objs; - for(auto obj : ai->visitableObjs) - { - if(conquerable(obj)) - objs.push_back(obj); - } - - for(auto h : cb->getHeroesInfo()) - { - std::vector 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; -} diff --git a/AI/Nullkiller/Goals/Conquer.h b/AI/Nullkiller/Goals/Conquer.h deleted file mode 100644 index 295930347..000000000 --- a/AI/Nullkiller/Goals/Conquer.h +++ /dev/null @@ -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 - { - public: - Conquer() - : CGoal(Goals::CONQUER) - { - priority = 10; - } - TGoalVec getAllPossibleSubgoals() override; - TSubgoal whatToDoToAchieve() override; - virtual bool operator==(const Conquer & other) const override; - }; -} diff --git a/AI/Nullkiller/Goals/Explore.cpp b/AI/Nullkiller/Goals/Explore.cpp deleted file mode 100644 index 2725f4d14..000000000 --- a/AI/Nullkiller/Goals/Explore.cpp +++ /dev/null @@ -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 cb; -extern boost::thread_specific_ptr 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 from; - std::vector 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 & tiles, std::vector & 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 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 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(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(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 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); -} diff --git a/AI/Nullkiller/Goals/Explore.h b/AI/Nullkiller/Goals/Explore.h deleted file mode 100644 index cf5dbb923..000000000 --- a/AI/Nullkiller/Goals/Explore.h +++ /dev/null @@ -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 -// { -// 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 & tiles, -// std::vector & out, -// CCallback * cbp, -// const TeamState * ts) const; -// -// int howManyTilesWillBeDiscovered(const int3 & pos, ExplorationHelper & scanResult) const; -// }; -//} diff --git a/AI/Nullkiller/Goals/GatherTroops.cpp b/AI/Nullkiller/Goals/GatherTroops.cpp deleted file mode 100644 index 05324a1fe..000000000 --- a/AI/Nullkiller/Goals/GatherTroops.cpp +++ /dev/null @@ -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 cb; -extern boost::thread_specific_ptr 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(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 -//} diff --git a/AI/Nullkiller/Goals/GatherTroops.h b/AI/Nullkiller/Goals/GatherTroops.h deleted file mode 100644 index 7d95a3fb0..000000000 --- a/AI/Nullkiller/Goals/GatherTroops.h +++ /dev/null @@ -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 - { - 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); - }; -} diff --git a/AI/Nullkiller/Goals/GetArtOfType.cpp b/AI/Nullkiller/Goals/GetArtOfType.cpp deleted file mode 100644 index 5d90f00ad..000000000 --- a/AI/Nullkiller/Goals/GetArtOfType.cpp +++ /dev/null @@ -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 cb; -extern boost::thread_specific_ptr 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)); -//} \ No newline at end of file diff --git a/AI/Nullkiller/Goals/GetArtOfType.h b/AI/Nullkiller/Goals/GetArtOfType.h deleted file mode 100644 index c20490c30..000000000 --- a/AI/Nullkiller/Goals/GetArtOfType.h +++ /dev/null @@ -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 - { - 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; - }; -} diff --git a/AI/Nullkiller/Goals/Goals.h b/AI/Nullkiller/Goals/Goals.h index 01a235395..02e4b733b 100644 --- a/AI/Nullkiller/Goals/Goals.h +++ b/AI/Nullkiller/Goals/Goals.h @@ -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" \ No newline at end of file diff --git a/AI/Nullkiller/Goals/VisitHero.cpp b/AI/Nullkiller/Goals/VisitHero.cpp deleted file mode 100644 index 63c348fe3..000000000 --- a/AI/Nullkiller/Goals/VisitHero.cpp +++ /dev/null @@ -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 cb; -extern boost::thread_specific_ptr ai; -extern FuzzyHelper * fh; - -using namespace Goals; - -bool VisitHero::operator==(const VisitHero & other) const -{ - return other.hero.h == hero.h && other.objid == objid; -} \ No newline at end of file diff --git a/AI/Nullkiller/Goals/VisitHero.h b/AI/Nullkiller/Goals/VisitHero.h deleted file mode 100644 index d172c88dd..000000000 --- a/AI/Nullkiller/Goals/VisitHero.h +++ /dev/null @@ -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 - { - public: - VisitHero() - : CGoal(Goals::VISIT_HERO) - { - } - VisitHero(int hid) - : CGoal(Goals::VISIT_HERO) - { - objid = hid; - } - virtual bool operator==(const VisitHero & other) const override; - }; -} diff --git a/AI/Nullkiller/Goals/VisitObj.cpp b/AI/Nullkiller/Goals/VisitObj.cpp deleted file mode 100644 index af2db3674..000000000 --- a/AI/Nullkiller/Goals/VisitObj.cpp +++ /dev/null @@ -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 cb; -extern boost::thread_specific_ptr 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); -} \ No newline at end of file diff --git a/AI/Nullkiller/Goals/VisitObj.h b/AI/Nullkiller/Goals/VisitObj.h deleted file mode 100644 index 43b34283e..000000000 --- a/AI/Nullkiller/Goals/VisitObj.h +++ /dev/null @@ -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 //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; - }; -} diff --git a/AI/Nullkiller/Goals/VisitTile.cpp b/AI/Nullkiller/Goals/VisitTile.cpp deleted file mode 100644 index 547560162..000000000 --- a/AI/Nullkiller/Goals/VisitTile.cpp +++ /dev/null @@ -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 cb; -extern boost::thread_specific_ptr ai; -extern FuzzyHelper * fh; - -using namespace Goals; - -bool VisitTile::operator==(const VisitTile & other) const -{ - return other.hero.h == hero.h && other.tile == tile; -} diff --git a/AI/Nullkiller/Goals/VisitTile.h b/AI/Nullkiller/Goals/VisitTile.h deleted file mode 100644 index 88ea45b1f..000000000 --- a/AI/Nullkiller/Goals/VisitTile.h +++ /dev/null @@ -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 - //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; - }; -} diff --git a/AI/Nullkiller/Markers/ArmyUpgrade.cpp b/AI/Nullkiller/Markers/ArmyUpgrade.cpp new file mode 100644 index 000000000..c5341d672 --- /dev/null +++ b/AI/Nullkiller/Markers/ArmyUpgrade.cpp @@ -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 cb; +extern boost::thread_specific_ptr 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(); +} \ No newline at end of file diff --git a/AI/Nullkiller/Markers/ArmyUpgrade.h b/AI/Nullkiller/Markers/ArmyUpgrade.h new file mode 100644 index 000000000..475abf519 --- /dev/null +++ b/AI/Nullkiller/Markers/ArmyUpgrade.h @@ -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 + { + 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; } + }; +} \ No newline at end of file diff --git a/AI/Nullkiller/Markers/HeroExchange.cpp b/AI/Nullkiller/Markers/HeroExchange.cpp new file mode 100644 index 000000000..aab4516cc --- /dev/null +++ b/AI/Nullkiller/Markers/HeroExchange.cpp @@ -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 cb; +extern boost::thread_specific_ptr 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; +} \ No newline at end of file diff --git a/AI/Nullkiller/Markers/HeroExchange.h b/AI/Nullkiller/Markers/HeroExchange.h new file mode 100644 index 000000000..20942d6a0 --- /dev/null +++ b/AI/Nullkiller/Markers/HeroExchange.h @@ -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 + { + 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; + }; +} \ No newline at end of file diff --git a/AI/Nullkiller/Goals/UnlockCluster.cpp b/AI/Nullkiller/Markers/UnlockCluster.cpp similarity index 100% rename from AI/Nullkiller/Goals/UnlockCluster.cpp rename to AI/Nullkiller/Markers/UnlockCluster.cpp diff --git a/AI/Nullkiller/Goals/UnlockCluster.h b/AI/Nullkiller/Markers/UnlockCluster.h similarity index 97% rename from AI/Nullkiller/Goals/UnlockCluster.h rename to AI/Nullkiller/Markers/UnlockCluster.h index 1abbde2a0..b55195087 100644 --- a/AI/Nullkiller/Goals/UnlockCluster.h +++ b/AI/Nullkiller/Markers/UnlockCluster.h @@ -9,7 +9,7 @@ */ #pragma once -#include "CGoal.h" +#include "../Goals/CGoal.h" #include "../Analyzers/ObjectClusterizer.h" diff --git a/AI/Nullkiller/Pathfinding/AINodeStorage.cpp b/AI/Nullkiller/Pathfinding/AINodeStorage.cpp index 2a3e77d66..40f47d701 100644 --- a/AI/Nullkiller/Pathfinding/AINodeStorage.cpp +++ b/AI/Nullkiller/Pathfinding/AINodeStorage.cpp @@ -1112,10 +1112,10 @@ AIPath::AIPath() std::shared_ptr 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(); diff --git a/AI/Nullkiller/Pathfinding/AINodeStorage.h b/AI/Nullkiller/Pathfinding/AINodeStorage.h index 2db675faf..2a982008a 100644 --- a/AI/Nullkiller/Pathfinding/AINodeStorage.h +++ b/AI/Nullkiller/Pathfinding/AINodeStorage.h @@ -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" diff --git a/AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp b/AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp index d1dca248d..acb9d6bc7 100644 --- a/AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp +++ b/AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp @@ -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 cb;