diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index 703461cc1..1ce6b6fd4 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -566,7 +566,7 @@ void AIGateway::initGameInterface(std::shared_ptr env, std::shared_ myCb->waitTillRealize = true; myCb->unlockGsWhenWaiting = true; - nullkiller->init(CB, playerID); + nullkiller->init(CB, this); retrieveVisitableObjs(); } @@ -828,7 +828,7 @@ void AIGateway::makeTurn() { for(const CGObjectInstance * obj : nullkiller->memory->visitableObjs) { - if(isWeeklyRevisitable(obj)) + if(isWeeklyRevisitable(nullkiller.get(), obj)) { nullkiller->memory->markObjectUnvisited(obj); } @@ -1152,6 +1152,11 @@ void AIGateway::retrieveVisitableObjs() { for(const CGObjectInstance * obj : myCb->getVisitableObjs(pos, false)) { + if(!obj->appearance) + { + logAi->error("Bad!"); + } + addVisitableObj(obj); } }); diff --git a/AI/Nullkiller/AIUtility.cpp b/AI/Nullkiller/AIUtility.cpp index 96c10efbc..0c05aae8d 100644 --- a/AI/Nullkiller/AIUtility.cpp +++ b/AI/Nullkiller/AIUtility.cpp @@ -163,14 +163,6 @@ bool HeroPtr::operator==(const HeroPtr & rhs) const return h == rhs.get(true); } -bool CDistanceSorter::operator()(const CGObjectInstance * lhs, const CGObjectInstance * rhs) const -{ - const CGPathNode * ln = ai->myCb->getPathsInfo(hero)->getPathInfo(lhs->visitablePos()); - const CGPathNode * rn = ai->myCb->getPathsInfo(hero)->getPathInfo(rhs->visitablePos()); - - return ln->getCost() < rn->getCost(); -} - bool isSafeToVisit(const CGHeroInstance * h, const CCreatureSet * heroArmy, uint64_t dangerStrength) { const ui64 heroStrength = h->getFightingStrength() * heroArmy->getArmyStrength(); @@ -235,11 +227,6 @@ bool isObjectPassable(const Nullkiller * ai, const CGObjectInstance * obj) return isObjectPassable(obj, ai->playerID, ai->cb->getPlayerRelations(obj->tempOwner, ai->playerID)); } -bool isObjectPassable(const CGObjectInstance * obj) -{ - return isObjectPassable(obj, ai->playerID, ai->myCb->getPlayerRelations(obj->tempOwner, ai->playerID)); -} - // Pathfinder internal helper bool isObjectPassable(const CGObjectInstance * obj, PlayerColor playerColor, PlayerRelations objectRelations) { @@ -306,7 +293,7 @@ bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2 return art1->getPrice() > art2->getPrice(); } -bool isWeeklyRevisitable(const CGObjectInstance * obj) +bool isWeeklyRevisitable(const Nullkiller * ai, const CGObjectInstance * obj) { if(!obj) return false; diff --git a/AI/Nullkiller/AIUtility.h b/AI/Nullkiller/AIUtility.h index 163e970f0..b08cffef7 100644 --- a/AI/Nullkiller/AIUtility.h +++ b/AI/Nullkiller/AIUtility.h @@ -70,7 +70,6 @@ extern const float SAFE_ATTACK_CONSTANT; extern const int GOLD_RESERVE; extern thread_local CCallback * cb; -extern thread_local AIGateway * ai; enum HeroRole { @@ -114,11 +113,11 @@ public: bool validAndSet() const; - template void serialize(Handler & h) + template void serialize(Handler & handler) { - h & this->h; - h & hid; - h & name; + handler & h; + handler & hid; + handler & name; } }; @@ -224,12 +223,11 @@ void foreach_neighbour(CCallback * cbp, const int3 & pos, const Func & foo) // a } bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater); -bool isObjectPassable(const CGObjectInstance * obj); bool isObjectPassable(const Nullkiller * ai, const CGObjectInstance * obj); bool isObjectPassable(const CGObjectInstance * obj, PlayerColor playerColor, PlayerRelations objectRelations); bool isBlockVisitObj(const int3 & pos); -bool isWeeklyRevisitable(const CGObjectInstance * obj); +bool isWeeklyRevisitable(const Nullkiller * ai, const CGObjectInstance * obj); bool isObjectRemovable(const CGObjectInstance * obj); //FIXME FIXME: move logic to object property! bool isSafeToVisit(const CGHeroInstance * h, uint64_t dangerStrength); @@ -245,18 +243,6 @@ uint64_t timeElapsed(std::chrono::time_point // todo: move to obj manager bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObjectInstance * obj); -class CDistanceSorter -{ - const CGHeroInstance * hero; - -public: - CDistanceSorter(const CGHeroInstance * hero) - : hero(hero) - { - } - bool operator()(const CGObjectInstance * lhs, const CGObjectInstance * rhs) const; -}; - template class SharedPool { diff --git a/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp b/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp index 69c2afb52..9b95fb18e 100644 --- a/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp +++ b/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp @@ -180,7 +180,7 @@ bool ObjectClusterizer::shouldVisitObject(const CGObjectInstance * obj) const auto playerRelations = ai->cb->getPlayerRelations(ai->playerID, obj->tempOwner); - if(playerRelations != PlayerRelations::ENEMIES && !isWeeklyRevisitable(obj)) + if(playerRelations != PlayerRelations::ENEMIES && !isWeeklyRevisitable(ai, obj)) { return false; } diff --git a/AI/Nullkiller/Behaviors/BuildingBehavior.cpp b/AI/Nullkiller/Behaviors/BuildingBehavior.cpp index 8cf713954..d0596f838 100644 --- a/AI/Nullkiller/Behaviors/BuildingBehavior.cpp +++ b/AI/Nullkiller/Behaviors/BuildingBehavior.cpp @@ -27,14 +27,14 @@ std::string BuildingBehavior::toString() const return "Build"; } -Goals::TGoalVec BuildingBehavior::decompose() const +Goals::TGoalVec BuildingBehavior::decompose(const Nullkiller * ai) const { Goals::TGoalVec tasks; - TResources resourcesRequired = ai->nullkiller->buildAnalyzer->getResourcesRequiredNow(); - TResources totalDevelopmentCost = ai->nullkiller->buildAnalyzer->getTotalResourcesRequired(); - TResources availableResources = ai->nullkiller->getFreeResources(); - TResources dailyIncome = ai->nullkiller->buildAnalyzer->getDailyIncome(); + TResources resourcesRequired = ai->buildAnalyzer->getResourcesRequiredNow(); + TResources totalDevelopmentCost = ai->buildAnalyzer->getTotalResourcesRequired(); + TResources availableResources = ai->getFreeResources(); + TResources dailyIncome = ai->buildAnalyzer->getDailyIncome(); logAi->trace("Free resources amount: %s", availableResources.toString()); @@ -46,8 +46,8 @@ Goals::TGoalVec BuildingBehavior::decompose() const resourcesRequired.toString(), totalDevelopmentCost.toString()); - auto & developmentInfos = ai->nullkiller->buildAnalyzer->getDevelopmentInfo(); - auto isGoldPreasureLow = !ai->nullkiller->buildAnalyzer->isGoldPreasureHigh(); + auto & developmentInfos = ai->buildAnalyzer->getDevelopmentInfo(); + auto isGoldPreasureLow = !ai->buildAnalyzer->isGoldPreasureHigh(); for(auto & developmentInfo : developmentInfos) { @@ -57,7 +57,7 @@ Goals::TGoalVec BuildingBehavior::decompose() const { if(buildingInfo.notEnoughRes) { - if(ai->nullkiller->getLockedResources().canAfford(buildingInfo.buildCost)) + if(ai->getLockedResources().canAfford(buildingInfo.buildCost)) continue; Composition composition; diff --git a/AI/Nullkiller/Behaviors/BuildingBehavior.h b/AI/Nullkiller/Behaviors/BuildingBehavior.h index 4836d1cb0..7b44be981 100644 --- a/AI/Nullkiller/Behaviors/BuildingBehavior.h +++ b/AI/Nullkiller/Behaviors/BuildingBehavior.h @@ -25,7 +25,7 @@ namespace Goals { } - Goals::TGoalVec decompose() const override; + Goals::TGoalVec decompose(const Nullkiller * ai) const override; std::string toString() const override; bool operator==(const BuildingBehavior & other) const override { diff --git a/AI/Nullkiller/Behaviors/BuyArmyBehavior.cpp b/AI/Nullkiller/Behaviors/BuyArmyBehavior.cpp index 3e8251dfd..c36109167 100644 --- a/AI/Nullkiller/Behaviors/BuyArmyBehavior.cpp +++ b/AI/Nullkiller/Behaviors/BuyArmyBehavior.cpp @@ -24,11 +24,11 @@ std::string BuyArmyBehavior::toString() const return "Buy army"; } -Goals::TGoalVec BuyArmyBehavior::decompose() const +Goals::TGoalVec BuyArmyBehavior::decompose(const Nullkiller * ai) const { Goals::TGoalVec tasks; - if(cb->getDate(Date::DAY) == 1) + if(ai->cb->getDate(Date::DAY) == 1) return tasks; auto heroes = cb->getHeroesInfo(); @@ -40,26 +40,26 @@ Goals::TGoalVec BuyArmyBehavior::decompose() const for(auto town : cb->getTownsInfo()) { - auto townArmyAvailableToBuy = ai->nullkiller->armyManager->getArmyAvailableToBuyAsCCreatureSet( + auto townArmyAvailableToBuy = ai->armyManager->getArmyAvailableToBuyAsCCreatureSet( town, - ai->nullkiller->getFreeResources()); + ai->getFreeResources()); for(const CGHeroInstance * targetHero : heroes) { - if(ai->nullkiller->buildAnalyzer->isGoldPreasureHigh() && !town->hasBuilt(BuildingID::CITY_HALL)) + if(ai->buildAnalyzer->isGoldPreasureHigh() && !town->hasBuilt(BuildingID::CITY_HALL)) { continue; } - if(ai->nullkiller->heroManager->getHeroRole(targetHero) == HeroRole::MAIN) + if(ai->heroManager->getHeroRole(targetHero) == HeroRole::MAIN) { - auto reinforcement = ai->nullkiller->armyManager->howManyReinforcementsCanGet( + auto reinforcement = ai->armyManager->howManyReinforcementsCanGet( targetHero, targetHero, &*townArmyAvailableToBuy); if(reinforcement) - vstd::amin(reinforcement, ai->nullkiller->armyManager->howManyReinforcementsCanBuy(town->getUpperArmy(), town)); + vstd::amin(reinforcement, ai->armyManager->howManyReinforcementsCanBuy(town->getUpperArmy(), town)); if(reinforcement) { diff --git a/AI/Nullkiller/Behaviors/BuyArmyBehavior.h b/AI/Nullkiller/Behaviors/BuyArmyBehavior.h index 909e7221c..d8f986a5d 100644 --- a/AI/Nullkiller/Behaviors/BuyArmyBehavior.h +++ b/AI/Nullkiller/Behaviors/BuyArmyBehavior.h @@ -20,11 +20,7 @@ namespace Goals class BuyArmyBehavior : public CGoal { public: - BuyArmyBehavior() - { - } - - Goals::TGoalVec decompose() const override; + Goals::TGoalVec decompose(const Nullkiller * ai) const override; std::string toString() const override; bool operator==(const BuyArmyBehavior & other) const override { diff --git a/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp b/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp index 5a79c057e..c061faf13 100644 --- a/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp +++ b/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp @@ -47,7 +47,7 @@ bool CaptureObjectsBehavior::operator==(const CaptureObjectsBehavior & other) co && vectorEquals(objectSubTypes, other.objectSubTypes); } -Goals::TGoalVec CaptureObjectsBehavior::getVisitGoals(const std::vector & paths, Nullkiller * nullkiller, const CGObjectInstance * objToVisit) +Goals::TGoalVec CaptureObjectsBehavior::getVisitGoals(const std::vector & paths, const Nullkiller * nullkiller, const CGObjectInstance * objToVisit) { Goals::TGoalVec tasks; @@ -96,7 +96,7 @@ Goals::TGoalVec CaptureObjectsBehavior::getVisitGoals(const std::vector auto firstBlockedAction = path.getFirstBlockedAction(); if(firstBlockedAction) { - auto subGoal = firstBlockedAction->decompose(path.targetHero); + auto subGoal = firstBlockedAction->decompose(nullkiller, path.targetHero); #if NKAI_TRACE_LEVEL >= 2 logAi->trace("Decomposing special action %s returns %s", firstBlockedAction->toString(), subGoal->toString()); @@ -167,83 +167,80 @@ Goals::TGoalVec CaptureObjectsBehavior::getVisitGoals(const std::vector return tasks; } -Goals::TGoalVec CaptureObjectsBehavior::decompose() const +void CaptureObjectsBehavior::decomposeObjects( + Goals::TGoalVec & result, + const std::vector & objs, + const Nullkiller * nullkiller) const { - Goals::TGoalVec tasks; + if(objs.empty()) + { + return; + } + std::mutex sync; - Nullkiller * nullkiller = ai->nullkiller.get(); + logAi->debug("Scanning objects, count %d", objs.size()); - auto captureObjects = [&](const std::vector & objs) -> void - { - if(objs.empty()) + // tbb::blocked_range r(0, objs.size()); + tbb::parallel_for( + tbb::blocked_range(0, objs.size()), + [this, &objs, &sync, &result, nullkiller](const tbb::blocked_range & r) { - return; - } + std::vector paths; + Goals::TGoalVec tasksLocal; - logAi->debug("Scanning objects, count %d", objs.size()); - - tbb::parallel_for( - tbb::blocked_range(0, objs.size()), - [this, &objs, &sync, &tasks, nullkiller](const tbb::blocked_range & r) + for(auto i = r.begin(); i != r.end(); i++) { - std::vector paths; - Goals::TGoalVec tasksLocal; + auto objToVisit = objs[i]; - for(auto i = r.begin(); i != r.end(); i++) - { - auto objToVisit = objs[i]; - - if(!objectMatchesFilter(objToVisit)) - continue; + if(!objectMatchesFilter(objToVisit)) + continue; #if NKAI_TRACE_LEVEL >= 1 - logAi->trace("Checking object %s, %s", objToVisit->getObjectName(), objToVisit->visitablePos().toString()); + logAi->trace("Checking object %s, %s", objToVisit->getObjectName(), objToVisit->visitablePos().toString()); #endif - const int3 pos = objToVisit->visitablePos(); - bool useObjectGraph = nullkiller->settings->isObjectGraphAllowed() - && nullkiller->getScanDepth() != ScanDepth::SMALL; - - nullkiller->pathfinder->calculatePathInfo(paths, pos, useObjectGraph); - - std::vector> waysToVisitObj; - std::shared_ptr closestWay; + nullkiller->pathfinder->calculatePathInfo(paths, objToVisit->visitablePos(), nullkiller->settings->isObjectGraphAllowed()); #if NKAI_TRACE_LEVEL >= 1 - logAi->trace("Found %d paths", paths.size()); + logAi->trace("Found %d paths", paths.size()); #endif - vstd::concatenate(tasksLocal, getVisitGoals(paths, nullkiller, objToVisit)); - } + vstd::concatenate(tasksLocal, getVisitGoals(paths, nullkiller, objToVisit)); + } - vstd::erase_if(tasksLocal, [](TSubgoal task) -> bool - { - return task->invalid(); - }); + std::lock_guard lock(sync); + vstd::concatenate(result, tasksLocal); + }); +} - std::lock_guard lock(sync); +Goals::TGoalVec CaptureObjectsBehavior::decompose(const Nullkiller * ai) const +{ + Goals::TGoalVec tasks; - vstd::concatenate(tasks, tasksLocal); - }); - }; + vstd::erase_if(tasks, [](TSubgoal task) -> bool + { + return task->invalid(); + }); if(specificObjects) { - captureObjects(objectsToCapture); + decomposeObjects(tasks, objectsToCapture, ai); } else if(objectTypes.size()) { - captureObjects( + decomposeObjects( + tasks, std::vector( - nullkiller->memory->visitableObjs.begin(), - nullkiller->memory->visitableObjs.end())); + ai->memory->visitableObjs.begin(), + ai->memory->visitableObjs.end()), + ai); } else { - captureObjects(nullkiller->objectClusterizer->getNearbyObjects()); + decomposeObjects(tasks, ai->objectClusterizer->getNearbyObjects(), ai); - if(tasks.empty() || nullkiller->getScanDepth() != ScanDepth::SMALL) - captureObjects(nullkiller->objectClusterizer->getFarObjects()); + if(tasks.empty() || ai->getScanDepth() != ScanDepth::SMALL) + decomposeObjects(tasks, ai->objectClusterizer->getFarObjects(), ai); } return tasks; diff --git a/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.h b/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.h index 3f2c28696..b68815ea8 100644 --- a/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.h +++ b/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.h @@ -25,6 +25,7 @@ namespace Goals std::vector objectSubTypes; std::vector objectsToCapture; bool specificObjects; + public: CaptureObjectsBehavior() :CGoal(CAPTURE_OBJECTS) @@ -48,7 +49,7 @@ namespace Goals specificObjects = true; } - Goals::TGoalVec decompose() const override; + Goals::TGoalVec decompose(const Nullkiller * ai) const override; std::string toString() const override; CaptureObjectsBehavior & ofType(int type) @@ -67,10 +68,14 @@ namespace Goals bool operator==(const CaptureObjectsBehavior & other) const override; - static Goals::TGoalVec getVisitGoals(const std::vector & paths, Nullkiller * nullkiller, const CGObjectInstance * objToVisit = nullptr); + static Goals::TGoalVec getVisitGoals(const std::vector & paths, const Nullkiller * nullkiller, const CGObjectInstance * objToVisit = nullptr); private: bool objectMatchesFilter(const CGObjectInstance * obj) const; + void decomposeObjects( + Goals::TGoalVec & result, + const std::vector & objs, + const Nullkiller * nullkiller) const; }; } diff --git a/AI/Nullkiller/Behaviors/ClusterBehavior.cpp b/AI/Nullkiller/Behaviors/ClusterBehavior.cpp index c5fed8cdf..dc38363a4 100644 --- a/AI/Nullkiller/Behaviors/ClusterBehavior.cpp +++ b/AI/Nullkiller/Behaviors/ClusterBehavior.cpp @@ -26,23 +26,23 @@ std::string ClusterBehavior::toString() const return "Unlock Clusters"; } -Goals::TGoalVec ClusterBehavior::decompose() const +Goals::TGoalVec ClusterBehavior::decompose(const Nullkiller * ai) const { Goals::TGoalVec tasks; - auto clusters = ai->nullkiller->objectClusterizer->getLockedClusters(); + auto clusters = ai->objectClusterizer->getLockedClusters(); for(auto cluster : clusters) { - vstd::concatenate(tasks, decomposeCluster(cluster)); + vstd::concatenate(tasks, decomposeCluster(ai, cluster)); } return tasks; } -Goals::TGoalVec ClusterBehavior::decomposeCluster(std::shared_ptr cluster) const +Goals::TGoalVec ClusterBehavior::decomposeCluster(const Nullkiller * ai, std::shared_ptr cluster) const { auto center = cluster->calculateCenter(); - auto paths = ai->nullkiller->pathfinder->getPathInfo(center->visitablePos(), ai->nullkiller->settings->isObjectGraphAllowed()); + auto paths = ai->pathfinder->getPathInfo(center->visitablePos(), ai->settings->isObjectGraphAllowed()); auto blockerPos = cluster->blocker->visitablePos(); std::vector blockerPaths; @@ -65,7 +65,7 @@ Goals::TGoalVec ClusterBehavior::decomposeCluster(std::shared_ptr logAi->trace("Checking path %s", path->toString()); #endif - auto blocker = ai->nullkiller->objectClusterizer->getBlocker(*path); + auto blocker = ai->objectClusterizer->getBlocker(*path); if(blocker != cluster->blocker) { @@ -83,7 +83,7 @@ Goals::TGoalVec ClusterBehavior::decomposeCluster(std::shared_ptr { clonedPath.nodes.insert(clonedPath.nodes.begin(), *node); - if(node->coord == blockerPos || cb->getGuardingCreaturePosition(node->coord) == blockerPos) + if(node->coord == blockerPos || ai->cb->getGuardingCreaturePosition(node->coord) == blockerPos) break; } @@ -100,7 +100,7 @@ Goals::TGoalVec ClusterBehavior::decomposeCluster(std::shared_ptr logAi->trace("Decompose unlock paths"); #endif - auto unlockTasks = CaptureObjectsBehavior::getVisitGoals(blockerPaths, ai->nullkiller.get()); + auto unlockTasks = CaptureObjectsBehavior::getVisitGoals(blockerPaths, ai); for(int i = 0; i < paths.size(); i++) { diff --git a/AI/Nullkiller/Behaviors/ClusterBehavior.h b/AI/Nullkiller/Behaviors/ClusterBehavior.h index c19642a8d..1e898ff7b 100644 --- a/AI/Nullkiller/Behaviors/ClusterBehavior.h +++ b/AI/Nullkiller/Behaviors/ClusterBehavior.h @@ -28,7 +28,7 @@ namespace Goals { } - TGoalVec decompose() const override; + TGoalVec decompose(const Nullkiller * ai) const override; std::string toString() const override; bool operator==(const ClusterBehavior & other) const override @@ -37,7 +37,7 @@ namespace Goals } private: - Goals::TGoalVec decomposeCluster(std::shared_ptr cluster) const; + Goals::TGoalVec decomposeCluster(const Nullkiller * ai, std::shared_ptr cluster) const; }; } diff --git a/AI/Nullkiller/Behaviors/DefenceBehavior.cpp b/AI/Nullkiller/Behaviors/DefenceBehavior.cpp index 026a122cc..f6bf88ced 100644 --- a/AI/Nullkiller/Behaviors/DefenceBehavior.cpp +++ b/AI/Nullkiller/Behaviors/DefenceBehavior.cpp @@ -34,21 +34,21 @@ std::string DefenceBehavior::toString() const return "Defend towns"; } -Goals::TGoalVec DefenceBehavior::decompose() const +Goals::TGoalVec DefenceBehavior::decompose(const Nullkiller * ai) const { Goals::TGoalVec tasks; - for(auto town : cb->getTownsInfo()) + for(auto town : ai->cb->getTownsInfo()) { - evaluateDefence(tasks, town); + evaluateDefence(tasks, town, ai); } return tasks; } -bool isThreatUnderControl(const CGTownInstance * town, const HitMapInfo & threat, const std::vector & paths) +bool isThreatUnderControl(const CGTownInstance * town, const HitMapInfo & threat, const Nullkiller * ai, const std::vector & paths) { - int dayOfWeek = cb->getDate(Date::DAY_OF_WEEK); + int dayOfWeek = ai->cb->getDate(Date::DAY_OF_WEEK); for(const AIPath & path : paths) { @@ -81,14 +81,15 @@ void handleCounterAttack( const CGTownInstance * town, const HitMapInfo & threat, const HitMapInfo & maximumDanger, + const Nullkiller * ai, Goals::TGoalVec & tasks) { if(threat.hero.validAndSet() && threat.turn <= 1 && (threat.danger == maximumDanger.danger || threat.turn < maximumDanger.turn)) { - auto heroCapturingPaths = ai->nullkiller->pathfinder->getPathInfo(threat.hero->visitablePos()); - auto goals = CaptureObjectsBehavior::getVisitGoals(heroCapturingPaths, ai->nullkiller.get(), threat.hero.get()); + auto heroCapturingPaths = ai->pathfinder->getPathInfo(threat.hero->visitablePos()); + auto goals = CaptureObjectsBehavior::getVisitGoals(heroCapturingPaths, ai, threat.hero.get()); for(int i = 0; i < heroCapturingPaths.size(); i++) { @@ -106,9 +107,9 @@ void handleCounterAttack( } } -bool handleGarrisonHeroFromPreviousTurn(const CGTownInstance * town, Goals::TGoalVec & tasks) +bool handleGarrisonHeroFromPreviousTurn(const CGTownInstance * town, Goals::TGoalVec & tasks, const Nullkiller * ai) { - if(ai->nullkiller->isHeroLocked(town->garrisonHero.get())) + if(ai->isHeroLocked(town->garrisonHero.get())) { logAi->trace( "Hero %s in garrison of town %s is supposed to defend the town", @@ -120,7 +121,7 @@ bool handleGarrisonHeroFromPreviousTurn(const CGTownInstance * town, Goals::TGoa if(!town->visitingHero) { - if(cb->getHeroCount(ai->playerID, false) < GameConstants::MAX_HEROES_PER_PLAYER) + if(ai->cb->getHeroCount(ai->playerID, false) < GameConstants::MAX_HEROES_PER_PLAYER) { logAi->trace( "Extracting hero %s from garrison of town %s", @@ -131,10 +132,10 @@ bool handleGarrisonHeroFromPreviousTurn(const CGTownInstance * town, Goals::TGoa return true; } - else if(ai->nullkiller->heroManager->getHeroRole(town->garrisonHero.get()) == HeroRole::MAIN) + else if(ai->heroManager->getHeroRole(town->garrisonHero.get()) == HeroRole::MAIN) { auto armyDismissLimit = 1000; - auto heroToDismiss = ai->nullkiller->heroManager->findWeakHeroToDismiss(armyDismissLimit); + auto heroToDismiss = ai->heroManager->findWeakHeroToDismiss(armyDismissLimit); if(heroToDismiss) { @@ -148,16 +149,16 @@ bool handleGarrisonHeroFromPreviousTurn(const CGTownInstance * town, Goals::TGoa return false; } -void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town) const +void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town, const Nullkiller * ai) const { logAi->trace("Evaluating defence for %s", town->getNameTranslated()); - auto threatNode = ai->nullkiller->dangerHitMap->getObjectThreat(town); - std::vector threats = ai->nullkiller->dangerHitMap->getTownThreats(town); + auto threatNode = ai->dangerHitMap->getObjectThreat(town); + std::vector threats = ai->dangerHitMap->getTownThreats(town); threats.push_back(threatNode.fastestDanger); // no guarantee that fastest danger will be there - if(town->garrisonHero && handleGarrisonHeroFromPreviousTurn(town, tasks)) + if(town->garrisonHero && handleGarrisonHeroFromPreviousTurn(town, tasks, ai)) { return; } @@ -169,7 +170,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta return; } - uint64_t reinforcement = ai->nullkiller->armyManager->howManyReinforcementsCanBuy(town->getUpperArmy(), town); + uint64_t reinforcement = ai->armyManager->howManyReinforcementsCanBuy(town->getUpperArmy(), town); if(reinforcement) { @@ -177,7 +178,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta tasks.push_back(Goals::sptr(Goals::BuyArmy(town, reinforcement).setpriority(0.5f))); } - auto paths = ai->nullkiller->pathfinder->getPathInfo(town->visitablePos()); + auto paths = ai->pathfinder->getPathInfo(town->visitablePos()); for(auto & threat : threats) { @@ -188,14 +189,14 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta std::to_string(threat.turn), threat.hero ? threat.hero->getNameTranslated() : std::string("")); - handleCounterAttack(town, threat, threatNode.maximumDanger, tasks); + handleCounterAttack(town, threat, threatNode.maximumDanger, ai, tasks); - if(isThreatUnderControl(town, threat, paths)) + if(isThreatUnderControl(town, threat, ai, paths)) { continue; } - evaluateRecruitingHero(tasks, threat, town); + evaluateRecruitingHero(tasks, threat, town, ai); if(paths.empty()) { @@ -274,7 +275,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta // main without army and visiting scout with army, very specific case if(town->visitingHero && town->getUpperArmy()->stacksCount() == 0 && path.targetHero != town->visitingHero.get() && path.exchangeCount == 1 && path.turn() == 0 - && ai->nullkiller->heroManager->evaluateHero(path.targetHero) > ai->nullkiller->heroManager->evaluateHero(town->visitingHero.get()) + && ai->heroManager->evaluateHero(path.targetHero) > ai->heroManager->evaluateHero(town->visitingHero.get()) && 10 * path.targetHero->getTotalStrength() < town->visitingHero->getTotalStrength()) { path.heroArmy = town->visitingHero.get(); @@ -293,7 +294,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta if(threat.turn == 0 || (path.turn() <= threat.turn && path.getHeroStrength() * SAFE_ATTACK_CONSTANT >= threat.danger)) { - if(ai->nullkiller->arePathHeroesLocked(path)) + if(ai->arePathHeroesLocked(path)) { #if NKAI_TRACE_LEVEL >= 1 logAi->trace("Can not move %s to defend town %s. Path is locked.", @@ -344,7 +345,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta { if(town->garrisonHero) { - if(ai->nullkiller->heroManager->getHeroRole(town->visitingHero.get()) == HeroRole::SCOUT + if(ai->heroManager->getHeroRole(town->visitingHero.get()) == HeroRole::SCOUT && town->visitingHero->getArmyStrength() < path.heroArmy->getArmyStrength() / 20) { if(path.turn() == 0) @@ -378,7 +379,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta auto firstBlockedAction = path.getFirstBlockedAction(); if(firstBlockedAction) { - auto subGoal = firstBlockedAction->decompose(path.targetHero); + auto subGoal = firstBlockedAction->decompose(ai, path.targetHero); #if NKAI_TRACE_LEVEL >= 2 logAi->trace("Decomposing special action %s returns %s", firstBlockedAction->toString(), subGoal->toString()); @@ -402,19 +403,19 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta logAi->debug("Found %d tasks", tasks.size()); } -void DefenceBehavior::evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitMapInfo & threat, const CGTownInstance * town) const +void DefenceBehavior::evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitMapInfo & threat, const CGTownInstance * town, const Nullkiller * ai) const { if(town->hasBuilt(BuildingID::TAVERN) - && cb->getResourceAmount(EGameResID::GOLD) > GameConstants::HERO_GOLD_COST) + && ai->cb->getResourceAmount(EGameResID::GOLD) > GameConstants::HERO_GOLD_COST) { - auto heroesInTavern = cb->getAvailableHeroes(town); + auto heroesInTavern = ai->cb->getAvailableHeroes(town); for(auto hero : heroesInTavern) { if(hero->getTotalStrength() < threat.danger) continue; - auto myHeroes = cb->getHeroesInfo(); + auto myHeroes = ai->cb->getHeroesInfo(); #if NKAI_TRACE_LEVEL >= 1 logAi->trace("Hero %s can be recruited to defend %s", hero->getObjectName(), town->getObjectName()); @@ -448,9 +449,9 @@ void DefenceBehavior::evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitM if(heroToDismiss && heroToDismiss->getArmyStrength() + 500 > hero->getArmyStrength()) continue; } - else if(ai->nullkiller->heroManager->heroCapReached()) + else if(ai->heroManager->heroCapReached()) { - heroToDismiss = ai->nullkiller->heroManager->findWeakHeroToDismiss(hero->getArmyStrength()); + heroToDismiss = ai->heroManager->findWeakHeroToDismiss(hero->getArmyStrength()); if(!heroToDismiss) continue; diff --git a/AI/Nullkiller/Behaviors/DefenceBehavior.h b/AI/Nullkiller/Behaviors/DefenceBehavior.h index 18d577c66..3f27746de 100644 --- a/AI/Nullkiller/Behaviors/DefenceBehavior.h +++ b/AI/Nullkiller/Behaviors/DefenceBehavior.h @@ -20,7 +20,6 @@ struct HitMapInfo; namespace Goals { - class DefenceBehavior : public CGoal { public: @@ -29,7 +28,7 @@ namespace Goals { } - Goals::TGoalVec decompose() const override; + Goals::TGoalVec decompose(const Nullkiller * ai) const override; std::string toString() const override; bool operator==(const DefenceBehavior & other) const override @@ -38,8 +37,8 @@ namespace Goals } private: - void evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town) const; - void evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitMapInfo & threat, const CGTownInstance * town) const; + void evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town, const Nullkiller * ai) const; + void evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitMapInfo & threat, const CGTownInstance * town, const Nullkiller * ai) const; }; } diff --git a/AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp b/AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp index c4c1fd612..689ee3cf7 100644 --- a/AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp +++ b/AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp @@ -30,11 +30,11 @@ std::string GatherArmyBehavior::toString() const return "Gather army"; } -Goals::TGoalVec GatherArmyBehavior::decompose() const +Goals::TGoalVec GatherArmyBehavior::decompose(const Nullkiller * ai) const { Goals::TGoalVec tasks; - auto heroes = cb->getHeroesInfo(); + auto heroes = ai->cb->getHeroesInfo(); if(heroes.empty()) { @@ -43,33 +43,33 @@ Goals::TGoalVec GatherArmyBehavior::decompose() const for(const CGHeroInstance * hero : heroes) { - if(ai->nullkiller->heroManager->getHeroRole(hero) == HeroRole::MAIN) + if(ai->heroManager->getHeroRole(hero) == HeroRole::MAIN) { - vstd::concatenate(tasks, deliverArmyToHero(hero)); + vstd::concatenate(tasks, deliverArmyToHero(ai, hero)); } } - auto towns = cb->getTownsInfo(); + auto towns = ai->cb->getTownsInfo(); for(const CGTownInstance * town : towns) { - vstd::concatenate(tasks, upgradeArmy(town)); + vstd::concatenate(tasks, upgradeArmy(ai, town)); } return tasks; } -Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * hero) const +Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const Nullkiller * ai, const CGHeroInstance * hero) const { Goals::TGoalVec tasks; const int3 pos = hero->visitablePos(); - auto targetHeroScore = ai->nullkiller->heroManager->evaluateHero(hero); + auto targetHeroScore = ai->heroManager->evaluateHero(hero); #if NKAI_TRACE_LEVEL >= 1 logAi->trace("Checking ways to gaher army for hero %s, %s", hero->getObjectName(), pos.toString()); #endif - auto paths = ai->nullkiller->pathfinder->getPathInfo(pos, ai->nullkiller->settings->isObjectGraphAllowed()); + auto paths = ai->pathfinder->getPathInfo(pos, ai->settings->isObjectGraphAllowed()); #if NKAI_TRACE_LEVEL >= 1 logAi->trace("Gather army found %d paths", paths.size()); @@ -89,7 +89,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her continue; } - if(path.turn() > 0 && ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path)) + if(path.turn() > 0 && ai->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path)) { #if NKAI_TRACE_LEVEL >= 2 logAi->trace("Ignore path. Target hero can be killed by enemy. Our power %lld", path.heroArmy->getArmyStrength()); @@ -97,7 +97,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her continue; } - if(ai->nullkiller->arePathHeroesLocked(path)) + if(ai->arePathHeroesLocked(path)) { #if NKAI_TRACE_LEVEL >= 2 logAi->trace("Ignore path because of locked hero"); @@ -107,7 +107,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her HeroExchange heroExchange(hero, path); - uint64_t armyValue = heroExchange.getReinforcementArmyStrength(); + uint64_t armyValue = heroExchange.getReinforcementArmyStrength(ai); float armyRatio = (float)armyValue / hero->getArmyStrength(); // avoid transferring very small amount of army @@ -126,11 +126,11 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her { if(!node.targetHero) continue; - auto heroRole = ai->nullkiller->heroManager->getHeroRole(node.targetHero); + auto heroRole = ai->heroManager->getHeroRole(node.targetHero); if(heroRole == HeroRole::MAIN) { - auto score = ai->nullkiller->heroManager->evaluateHero(node.targetHero); + auto score = ai->heroManager->evaluateHero(node.targetHero); if(score >= targetHeroScore) { @@ -174,7 +174,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her if(hero->inTownGarrison && path.turn() == 0) { - auto lockReason = ai->nullkiller->getHeroLockedReason(hero); + auto lockReason = ai->getHeroLockedReason(hero); if(path.targetHero->visitedTown == hero->visitedTown) { @@ -201,7 +201,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her #if NKAI_TRACE_LEVEL >= 2 logAi->trace("Action is blocked. Considering decomposition."); #endif - auto subGoal = blockedAction->decompose(path.targetHero); + auto subGoal = blockedAction->decompose(ai, path.targetHero); if(subGoal->invalid()) { @@ -221,18 +221,18 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her return tasks; } -Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader) const +Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const Nullkiller * ai, const CGTownInstance * upgrader) const { Goals::TGoalVec tasks; const int3 pos = upgrader->visitablePos(); - TResources availableResources = ai->nullkiller->getFreeResources(); + TResources availableResources = ai->getFreeResources(); #if NKAI_TRACE_LEVEL >= 1 logAi->trace("Checking ways to upgrade army in town %s, %s", upgrader->getObjectName(), pos.toString()); #endif - auto paths = ai->nullkiller->pathfinder->getPathInfo(pos, ai->nullkiller->settings->isObjectGraphAllowed()); - auto goals = CaptureObjectsBehavior::getVisitGoals(paths, ai->nullkiller.get()); + auto paths = ai->pathfinder->getPathInfo(pos, ai->settings->isObjectGraphAllowed()); + auto goals = CaptureObjectsBehavior::getVisitGoals(paths, ai); std::vector> waysToVisitObj; @@ -244,9 +244,9 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader) for(const AIPath & path : paths) { - auto heroRole = ai->nullkiller->heroManager->getHeroRole(path.targetHero); + auto heroRole = ai->heroManager->getHeroRole(path.targetHero); - if(heroRole == HeroRole::MAIN && path.turn() < ai->nullkiller->settings->getScoutHeroTurnDistanceLimit()) + if(heroRole == HeroRole::MAIN && path.turn() < ai->settings->getScoutHeroTurnDistanceLimit()) hasMainAround = true; } @@ -275,7 +275,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader) continue; } - if(ai->nullkiller->arePathHeroesLocked(path)) + if(ai->arePathHeroesLocked(path)) { #if NKAI_TRACE_LEVEL >= 2 logAi->trace("Ignore path because of locked hero"); @@ -292,10 +292,10 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader) continue; } - auto heroRole = ai->nullkiller->heroManager->getHeroRole(path.targetHero); + auto heroRole = ai->heroManager->getHeroRole(path.targetHero); if(heroRole == HeroRole::SCOUT - && ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path)) + && ai->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path)) { #if NKAI_TRACE_LEVEL >= 2 logAi->trace("Ignore path. Target hero can be killed by enemy. Our power %lld", path.heroArmy->getArmyStrength()); @@ -303,17 +303,17 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader) continue; } - auto upgrade = ai->nullkiller->armyManager->calculateCreaturesUpgrade(path.heroArmy, upgrader, availableResources); + auto upgrade = ai->armyManager->calculateCreaturesUpgrade(path.heroArmy, upgrader, availableResources); if(!upgrader->garrisonHero && ( hasMainAround - || ai->nullkiller->heroManager->getHeroRole(path.targetHero) == HeroRole::MAIN)) + || ai->heroManager->getHeroRole(path.targetHero) == HeroRole::MAIN)) { ArmyUpgradeInfo armyToGetOrBuy; armyToGetOrBuy.addArmyToGet( - ai->nullkiller->armyManager->getBestArmy( + ai->armyManager->getBestArmy( path.targetHero, path.heroArmy, upgrader->getUpperArmy())); @@ -321,11 +321,11 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader) armyToGetOrBuy.upgradeValue -= path.heroArmy->getArmyStrength(); armyToGetOrBuy.addArmyToBuy( - ai->nullkiller->armyManager->toSlotInfo( - ai->nullkiller->armyManager->getArmyAvailableToBuy( + ai->armyManager->toSlotInfo( + ai->armyManager->getArmyAvailableToBuy( path.heroArmy, upgrader, - ai->nullkiller->getFreeResources(), + ai->getFreeResources(), path.turn()))); upgrade.upgradeValue += armyToGetOrBuy.upgradeValue; @@ -334,17 +334,17 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader) if(!upgrade.upgradeValue && armyToGetOrBuy.upgradeValue > 20000 - && ai->nullkiller->heroManager->canRecruitHero(town) - && path.turn() < ai->nullkiller->settings->getScoutHeroTurnDistanceLimit()) + && ai->heroManager->canRecruitHero(town) + && path.turn() < ai->settings->getScoutHeroTurnDistanceLimit()) { for(auto hero : cb->getAvailableHeroes(town)) { - auto scoutReinforcement = ai->nullkiller->armyManager->howManyReinforcementsCanBuy(hero, town) - + ai->nullkiller->armyManager->howManyReinforcementsCanGet(hero, town); + auto scoutReinforcement = ai->armyManager->howManyReinforcementsCanBuy(hero, town) + + ai->armyManager->howManyReinforcementsCanGet(hero, town); if(scoutReinforcement >= armyToGetOrBuy.upgradeValue - && ai->nullkiller->getFreeGold() >20000 - && !ai->nullkiller->buildAnalyzer->isGoldPreasureHigh()) + && ai->getFreeGold() >20000 + && !ai->buildAnalyzer->isGoldPreasureHigh()) { Composition recruitHero; diff --git a/AI/Nullkiller/Behaviors/GatherArmyBehavior.h b/AI/Nullkiller/Behaviors/GatherArmyBehavior.h index b2ef06113..f2c05e1de 100644 --- a/AI/Nullkiller/Behaviors/GatherArmyBehavior.h +++ b/AI/Nullkiller/Behaviors/GatherArmyBehavior.h @@ -25,7 +25,7 @@ namespace Goals { } - TGoalVec decompose() const override; + TGoalVec decompose(const Nullkiller * ai) const override; std::string toString() const override; bool operator==(const GatherArmyBehavior & other) const override @@ -34,8 +34,8 @@ namespace Goals } private: - TGoalVec deliverArmyToHero(const CGHeroInstance * hero) const; - TGoalVec upgradeArmy(const CGTownInstance * upgrader) const; + TGoalVec deliverArmyToHero(const Nullkiller * ai, const CGHeroInstance * hero) const; + TGoalVec upgradeArmy(const Nullkiller * ai, const CGTownInstance * upgrader) const; }; } diff --git a/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp b/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp index 91c384ff1..fb9a7a754 100644 --- a/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp +++ b/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp @@ -24,12 +24,12 @@ std::string RecruitHeroBehavior::toString() const return "Recruit hero"; } -Goals::TGoalVec RecruitHeroBehavior::decompose() const +Goals::TGoalVec RecruitHeroBehavior::decompose(const Nullkiller * ai) const { Goals::TGoalVec tasks; - auto towns = cb->getTownsInfo(); + auto towns = ai->cb->getTownsInfo(); - auto ourHeroes = ai->nullkiller->heroManager->getHeroRoles(); + auto ourHeroes = ai->heroManager->getHeroRoles(); auto minScoreToHireMain = std::numeric_limits::max(); for(auto hero : ourHeroes) @@ -37,7 +37,7 @@ Goals::TGoalVec RecruitHeroBehavior::decompose() const if(hero.second != HeroRole::MAIN) continue; - auto newScore = ai->nullkiller->heroManager->evaluateHero(hero.first.get()); + auto newScore = ai->heroManager->evaluateHero(hero.first.get()); if(minScoreToHireMain > newScore) { @@ -48,13 +48,13 @@ Goals::TGoalVec RecruitHeroBehavior::decompose() const for(auto town : towns) { - if(ai->nullkiller->heroManager->canRecruitHero(town)) + if(ai->heroManager->canRecruitHero(town)) { - auto availableHeroes = cb->getAvailableHeroes(town); + auto availableHeroes = ai->cb->getAvailableHeroes(town); for(auto hero : availableHeroes) { - auto score = ai->nullkiller->heroManager->evaluateHero(hero); + auto score = ai->heroManager->evaluateHero(hero); if(score > minScoreToHireMain) { @@ -65,16 +65,16 @@ Goals::TGoalVec RecruitHeroBehavior::decompose() const int treasureSourcesCount = 0; - for(auto obj : ai->nullkiller->objectClusterizer->getNearbyObjects()) + for(auto obj : ai->objectClusterizer->getNearbyObjects()) { if((obj->ID == Obj::RESOURCE) || obj->ID == Obj::TREASURE_CHEST || obj->ID == Obj::CAMPFIRE - || isWeeklyRevisitable(obj) + || isWeeklyRevisitable(ai, obj) || obj->ID ==Obj::ARTIFACT) { auto tile = obj->visitablePos(); - auto closestTown = ai->nullkiller->dangerHitMap->getClosestTown(tile); + auto closestTown = ai->dangerHitMap->getClosestTown(tile); if(town == closestTown) treasureSourcesCount++; @@ -84,8 +84,8 @@ Goals::TGoalVec RecruitHeroBehavior::decompose() const if(treasureSourcesCount < 5 && (town->garrisonHero || town->getUpperArmy()->getArmyStrength() < 10000)) continue; - if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1 - || (ai->nullkiller->getFreeResources()[EGameResID::GOLD] > 10000 && !ai->nullkiller->buildAnalyzer->isGoldPreasureHigh())) + if(ai->cb->getHeroesInfo().size() < ai->cb->getTownsInfo().size() + 1 + || (ai->getFreeResources()[EGameResID::GOLD] > 10000 && !ai->buildAnalyzer->isGoldPreasureHigh())) { tasks.push_back(Goals::sptr(Goals::RecruitHero(town).setpriority(3))); } diff --git a/AI/Nullkiller/Behaviors/RecruitHeroBehavior.h b/AI/Nullkiller/Behaviors/RecruitHeroBehavior.h index e45c16e67..07232d9b9 100644 --- a/AI/Nullkiller/Behaviors/RecruitHeroBehavior.h +++ b/AI/Nullkiller/Behaviors/RecruitHeroBehavior.h @@ -25,7 +25,7 @@ namespace Goals { } - TGoalVec decompose() const override; + TGoalVec decompose(const Nullkiller * ai) const override; std::string toString() const override; bool operator==(const RecruitHeroBehavior & other) const override diff --git a/AI/Nullkiller/Behaviors/StartupBehavior.cpp b/AI/Nullkiller/Behaviors/StartupBehavior.cpp index 3a7f59f72..37573232d 100644 --- a/AI/Nullkiller/Behaviors/StartupBehavior.cpp +++ b/AI/Nullkiller/Behaviors/StartupBehavior.cpp @@ -41,9 +41,9 @@ const AIPath getShortestPath(const CGTownInstance * town, const std::vectornullkiller->pathfinder->getPathInfo(town->visitablePos()); + auto paths = ai->pathfinder->getPathInfo(town->visitablePos()); if(paths.empty()) return nullptr; @@ -59,9 +59,9 @@ const CGHeroInstance * getNearestHero(const CGTownInstance * town) return shortestPath.targetHero; } -bool needToRecruitHero(const CGTownInstance * startupTown) +bool needToRecruitHero(const Nullkiller * ai, const CGTownInstance * startupTown) { - if(!ai->nullkiller->heroManager->canRecruitHero(startupTown)) + if(!ai->heroManager->canRecruitHero(startupTown)) return false; if(!startupTown->garrisonHero && !startupTown->visitingHero) @@ -69,7 +69,7 @@ bool needToRecruitHero(const CGTownInstance * startupTown) int treasureSourcesCount = 0; - for(auto obj : ai->nullkiller->objectClusterizer->getNearbyObjects()) + for(auto obj : ai->objectClusterizer->getNearbyObjects()) { if((obj->ID == Obj::RESOURCE && dynamic_cast(obj)->resourceID() == EGameResID::GOLD) || obj->ID == Obj::TREASURE_CHEST @@ -91,10 +91,10 @@ bool needToRecruitHero(const CGTownInstance * startupTown) return cb->getHeroCount(ai->playerID, true) < basicCount + boost; } -Goals::TGoalVec StartupBehavior::decompose() const +Goals::TGoalVec StartupBehavior::decompose(const Nullkiller * ai) const { Goals::TGoalVec tasks; - auto towns = cb->getTownsInfo(); + auto towns = ai->cb->getTownsInfo(); if(!towns.size()) return tasks; @@ -103,38 +103,38 @@ Goals::TGoalVec StartupBehavior::decompose() const if(towns.size() > 1) { - startupTown = *vstd::maxElementByFun(towns, [](const CGTownInstance * town) -> float + startupTown = *vstd::maxElementByFun(towns, [ai](const CGTownInstance * town) -> float { if(town->garrisonHero) - return ai->nullkiller->heroManager->evaluateHero(town->garrisonHero.get()); + return ai->heroManager->evaluateHero(town->garrisonHero.get()); - auto closestHero = getNearestHero(town); + auto closestHero = getNearestHero(ai, town); if(closestHero) - return ai->nullkiller->heroManager->evaluateHero(closestHero); + return ai->heroManager->evaluateHero(closestHero); return 0; }); } if(!startupTown->hasBuilt(BuildingID::TAVERN) - && cb->canBuildStructure(startupTown, BuildingID::TAVERN) == EBuildingState::ALLOWED) + && ai->cb->canBuildStructure(startupTown, BuildingID::TAVERN) == EBuildingState::ALLOWED) { tasks.push_back(Goals::sptr(Goals::BuildThis(BuildingID::TAVERN, startupTown).setpriority(100))); return tasks; } - bool canRecruitHero = needToRecruitHero(startupTown); - auto closestHero = getNearestHero(startupTown); + bool canRecruitHero = needToRecruitHero(ai, startupTown); + auto closestHero = getNearestHero(ai, startupTown); if(closestHero) { if(!startupTown->visitingHero) { - if(ai->nullkiller->armyManager->howManyReinforcementsCanGet(startupTown->getUpperArmy(), startupTown->getUpperArmy(), closestHero) > 200) + if(ai->armyManager->howManyReinforcementsCanGet(startupTown->getUpperArmy(), startupTown->getUpperArmy(), closestHero) > 200) { - auto paths = ai->nullkiller->pathfinder->getPathInfo(startupTown->visitablePos()); + auto paths = ai->pathfinder->getPathInfo(startupTown->visitablePos()); if(paths.size()) { @@ -147,22 +147,22 @@ Goals::TGoalVec StartupBehavior::decompose() const else { auto visitingHero = startupTown->visitingHero.get(); - auto visitingHeroScore = ai->nullkiller->heroManager->evaluateHero(visitingHero); + auto visitingHeroScore = ai->heroManager->evaluateHero(visitingHero); if(startupTown->garrisonHero) { auto garrisonHero = startupTown->garrisonHero.get(); - auto garrisonHeroScore = ai->nullkiller->heroManager->evaluateHero(garrisonHero); + auto garrisonHeroScore = ai->heroManager->evaluateHero(garrisonHero); if(visitingHeroScore > garrisonHeroScore - || (ai->nullkiller->heroManager->getHeroRole(garrisonHero) == HeroRole::SCOUT && ai->nullkiller->heroManager->getHeroRole(visitingHero) == HeroRole::MAIN)) + || (ai->heroManager->getHeroRole(garrisonHero) == HeroRole::SCOUT && ai->heroManager->getHeroRole(visitingHero) == HeroRole::MAIN)) { - if(canRecruitHero || ai->nullkiller->armyManager->howManyReinforcementsCanGet(visitingHero, garrisonHero) > 200) + if(canRecruitHero || ai->armyManager->howManyReinforcementsCanGet(visitingHero, garrisonHero) > 200) { tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(startupTown, visitingHero, HeroLockedReason::STARTUP).setpriority(100))); } } - else if(ai->nullkiller->armyManager->howManyReinforcementsCanGet(garrisonHero, visitingHero) > 200) + else if(ai->armyManager->howManyReinforcementsCanGet(garrisonHero, visitingHero) > 200) { tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(startupTown, garrisonHero, HeroLockedReason::STARTUP).setpriority(100))); } @@ -170,7 +170,7 @@ Goals::TGoalVec StartupBehavior::decompose() const else if(canRecruitHero) { auto canPickTownArmy = startupTown->stacksCount() == 0 - || ai->nullkiller->armyManager->howManyReinforcementsCanGet(startupTown->visitingHero, startupTown) > 0; + || ai->armyManager->howManyReinforcementsCanGet(startupTown->visitingHero, startupTown) > 0; if(canPickTownArmy) { @@ -189,7 +189,7 @@ Goals::TGoalVec StartupBehavior::decompose() const { for(auto town : towns) { - if(!town->visitingHero && needToRecruitHero(town)) + if(!town->visitingHero && needToRecruitHero(ai, town)) { tasks.push_back(Goals::sptr(Goals::RecruitHero(town))); @@ -205,7 +205,7 @@ Goals::TGoalVec StartupBehavior::decompose() const if(town->garrisonHero && town->garrisonHero->movementPointsRemaining() && !town->visitingHero - && ai->nullkiller->getHeroLockedReason(town->garrisonHero) != HeroLockedReason::DEFENCE) + && ai->getHeroLockedReason(town->garrisonHero) != HeroLockedReason::DEFENCE) { tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(town, nullptr).setpriority(MIN_PRIORITY))); } diff --git a/AI/Nullkiller/Behaviors/StartupBehavior.h b/AI/Nullkiller/Behaviors/StartupBehavior.h index 0386b60a0..ce4118919 100644 --- a/AI/Nullkiller/Behaviors/StartupBehavior.h +++ b/AI/Nullkiller/Behaviors/StartupBehavior.h @@ -25,7 +25,7 @@ namespace Goals { } - TGoalVec decompose() const override; + TGoalVec decompose(const Nullkiller * ai) const override; std::string toString() const override; bool operator==(const StartupBehavior & other) const override diff --git a/AI/Nullkiller/Behaviors/StayAtTownBehavior.cpp b/AI/Nullkiller/Behaviors/StayAtTownBehavior.cpp index 34d7c609c..595830a66 100644 --- a/AI/Nullkiller/Behaviors/StayAtTownBehavior.cpp +++ b/AI/Nullkiller/Behaviors/StayAtTownBehavior.cpp @@ -27,10 +27,10 @@ std::string StayAtTownBehavior::toString() const return "StayAtTownBehavior"; } -Goals::TGoalVec StayAtTownBehavior::decompose() const +Goals::TGoalVec StayAtTownBehavior::decompose(const Nullkiller * ai) const { Goals::TGoalVec tasks; - auto towns = cb->getTownsInfo(); + auto towns = ai->cb->getTownsInfo(); if(!towns.size()) return tasks; @@ -42,7 +42,7 @@ Goals::TGoalVec StayAtTownBehavior::decompose() const if(!town->hasBuilt(BuildingID::MAGES_GUILD_1)) continue; - ai->nullkiller->pathfinder->calculatePathInfo(paths, town->visitablePos()); + ai->pathfinder->calculatePathInfo(paths, town->visitablePos()); for(auto & path : paths) { diff --git a/AI/Nullkiller/Behaviors/StayAtTownBehavior.h b/AI/Nullkiller/Behaviors/StayAtTownBehavior.h index 6287b85b0..d4f81da47 100644 --- a/AI/Nullkiller/Behaviors/StayAtTownBehavior.h +++ b/AI/Nullkiller/Behaviors/StayAtTownBehavior.h @@ -25,7 +25,7 @@ namespace Goals { } - TGoalVec decompose() const override; + TGoalVec decompose(const Nullkiller * ai) const override; std::string toString() const override; bool operator==(const StayAtTownBehavior & other) const override diff --git a/AI/Nullkiller/Engine/DeepDecomposer.cpp b/AI/Nullkiller/Engine/DeepDecomposer.cpp index 88fd3ed5b..468433653 100644 --- a/AI/Nullkiller/Engine/DeepDecomposer.cpp +++ b/AI/Nullkiller/Engine/DeepDecomposer.cpp @@ -26,6 +26,11 @@ namespace NKAI using namespace Goals; +DeepDecomposer::DeepDecomposer(const Nullkiller * ai) + :ai(ai), depth(0) +{ +} + void DeepDecomposer::reset() { decompositionCache.clear(); @@ -136,7 +141,7 @@ Goals::TSubgoal DeepDecomposer::aggregateGoals(int startDepth, TSubgoal last) Goals::TSubgoal DeepDecomposer::unwrapComposition(Goals::TSubgoal goal) { - return goal->goalType == Goals::COMPOSITION ? goal->decompose().back() : goal; + return goal->goalType == Goals::COMPOSITION ? goal->decompose(ai).back() : goal; } bool isEquivalentGoals(TSubgoal goal1, TSubgoal goal2) @@ -156,7 +161,7 @@ bool isEquivalentGoals(TSubgoal goal1, TSubgoal goal2) bool DeepDecomposer::isCompositionLoop(TSubgoal goal) { - auto goalsToTest = goal->goalType == Goals::COMPOSITION ? goal->decompose() : TGoalVec{goal}; + auto goalsToTest = goal->goalType == Goals::COMPOSITION ? goal->decompose(ai) : TGoalVec{goal}; for(auto goalToTest : goalsToTest) { @@ -206,7 +211,7 @@ TGoalVec DeepDecomposer::decomposeCached(TSubgoal goal, bool & fromCache) fromCache = false; - return goal->decompose(); + return goal->decompose(ai); } void DeepDecomposer::addToCache(TSubgoal goal) diff --git a/AI/Nullkiller/Engine/DeepDecomposer.h b/AI/Nullkiller/Engine/DeepDecomposer.h index 2f971f4cf..147c2c7d5 100644 --- a/AI/Nullkiller/Engine/DeepDecomposer.h +++ b/AI/Nullkiller/Engine/DeepDecomposer.h @@ -30,8 +30,10 @@ private: std::vector goals; std::vector decompositionCache; int depth; + const Nullkiller * ai; public: + DeepDecomposer(const Nullkiller * ai); void reset(); Goals::TGoalVec decompose(Goals::TSubgoal behavior, int depthLimit); diff --git a/AI/Nullkiller/Engine/Nullkiller.cpp b/AI/Nullkiller/Engine/Nullkiller.cpp index ac9aa2b6e..6bffeae35 100644 --- a/AI/Nullkiller/Engine/Nullkiller.cpp +++ b/AI/Nullkiller/Engine/Nullkiller.cpp @@ -37,10 +37,11 @@ Nullkiller::Nullkiller() settings = std::make_unique(); } -void Nullkiller::init(std::shared_ptr cb, PlayerColor playerID) +void Nullkiller::init(std::shared_ptr cb, AIGateway * gateway) { this->cb = cb; - this->playerID = playerID; + this->gateway = gateway; + this->playerID = gateway->playerID; baseGraph.reset(); @@ -59,7 +60,7 @@ void Nullkiller::init(std::shared_ptr cb, PlayerColor playerID) pathfinder.reset(new AIPathfinder(cb.get(), this)); armyManager.reset(new ArmyManager(cb.get(), this)); heroManager.reset(new HeroManager(cb.get(), this)); - decomposer.reset(new DeepDecomposer()); + decomposer.reset(new DeepDecomposer(this)); armyFormation.reset(new ArmyFormation(cb, this)); } @@ -120,12 +121,11 @@ void Nullkiller::resetAiState() lockedResources = TResources(); scanDepth = ScanDepth::MAIN_FULL; - playerID = ai->playerID; lockedHeroes.clear(); dangerHitMap->reset(); useHeroChain = true; - if(!baseGraph && ai->nullkiller->settings->isObjectGraphAllowed()) + if(!baseGraph && settings->isObjectGraphAllowed()) { baseGraph = std::make_unique(); baseGraph->updateGraph(this); @@ -253,6 +253,7 @@ void Nullkiller::makeTurn() for(int i = 1; i <= settings->getMaxPass(); i++) { + auto start = std::chrono::high_resolution_clock::now(); updateAiState(i); Goals::TTask bestTask = taskptr(Goals::Invalid()); @@ -342,6 +343,8 @@ void Nullkiller::makeTurn() return; } + logAi->debug("Decission madel in %ld", timeElapsed(start)); + executeTask(bestTask); if(i == settings->getMaxPass()) @@ -361,7 +364,7 @@ void Nullkiller::executeTask(Goals::TTask task) try { - task->accept(ai); + task->accept(gateway); logAi->trace("Task %s completed in %lld", taskDescr, timeElapsed(start)); } catch(goalFulfilledException &) diff --git a/AI/Nullkiller/Engine/Nullkiller.h b/AI/Nullkiller/Engine/Nullkiller.h index 02508bdae..ae6425b84 100644 --- a/AI/Nullkiller/Engine/Nullkiller.h +++ b/AI/Nullkiller/Engine/Nullkiller.h @@ -57,6 +57,7 @@ private: ScanDepth scanDepth; TResources lockedResources; bool useHeroChain; + AIGateway * gateway; public: static std::unique_ptr baseGraph; @@ -79,7 +80,7 @@ public: std::mutex aiStateMutex; Nullkiller(); - void init(std::shared_ptr cb, PlayerColor playerID); + void init(std::shared_ptr cb, AIGateway * gateway); void makeTurn(); bool isActive(const CGHeroInstance * hero) const { return activeHero == hero; } bool isHeroLocked(const CGHeroInstance * hero) const; diff --git a/AI/Nullkiller/Engine/PriorityEvaluator.cpp b/AI/Nullkiller/Engine/PriorityEvaluator.cpp index f9db14725..2c87d4a1c 100644 --- a/AI/Nullkiller/Engine/PriorityEvaluator.cpp +++ b/AI/Nullkiller/Engine/PriorityEvaluator.cpp @@ -709,7 +709,7 @@ public: Goals::HeroExchange & heroExchange = dynamic_cast(*task); - uint64_t armyStrength = heroExchange.getReinforcementArmyStrength(); + uint64_t armyStrength = heroExchange.getReinforcementArmyStrength(evaluationContext.evaluator.ai); evaluationContext.addNonCriticalStrategicalValue(2.0f * armyStrength / (float)heroExchange.hero.get()->getArmyStrength()); evaluationContext.heroRole = evaluationContext.evaluator.ai->heroManager->getHeroRole(heroExchange.hero.get()); @@ -1064,7 +1064,7 @@ EvaluationContext PriorityEvaluator::buildEvaluationContext(Goals::TSubgoal goal if(goal->goalType == Goals::COMPOSITION) { - parts = goal->decompose(); + parts = goal->decompose(ai); } else { diff --git a/AI/Nullkiller/Goals/AbstractGoal.h b/AI/Nullkiller/Goals/AbstractGoal.h index 2579c1e12..bbd2d5148 100644 --- a/AI/Nullkiller/Goals/AbstractGoal.h +++ b/AI/Nullkiller/Goals/AbstractGoal.h @@ -21,6 +21,7 @@ namespace NKAI struct HeroPtr; class AIGateway; class FuzzyHelper; +class Nullkiller; namespace Goals { @@ -128,7 +129,7 @@ namespace Goals return const_cast(this); } - virtual TGoalVec decompose() const + virtual TGoalVec decompose(const Nullkiller * ai) const { return TGoalVec(); } diff --git a/AI/Nullkiller/Goals/CGoal.h b/AI/Nullkiller/Goals/CGoal.h index 92e4a92a2..ab8db512b 100644 --- a/AI/Nullkiller/Goals/CGoal.h +++ b/AI/Nullkiller/Goals/CGoal.h @@ -54,9 +54,9 @@ namespace Goals virtual bool operator==(const T & other) const = 0; - TGoalVec decompose() const override + TGoalVec decompose(const Nullkiller * ai) const override { - TSubgoal single = decomposeSingle(); + TSubgoal single = decomposeSingle(ai); if(!single || single->invalid()) return {}; @@ -65,7 +65,7 @@ namespace Goals } protected: - virtual TSubgoal decomposeSingle() const + virtual TSubgoal decomposeSingle(const Nullkiller * ai) const { return TSubgoal(); } diff --git a/AI/Nullkiller/Goals/CaptureObject.cpp b/AI/Nullkiller/Goals/CaptureObject.cpp index 35a5d4417..7ca2ab266 100644 --- a/AI/Nullkiller/Goals/CaptureObject.cpp +++ b/AI/Nullkiller/Goals/CaptureObject.cpp @@ -35,9 +35,9 @@ std::string CaptureObject::toString() const return "Capture " + name + " at " + tile.toString(); } -TGoalVec CaptureObject::decompose() const +TGoalVec CaptureObject::decompose(const Nullkiller * ai) const { - return CaptureObjectsBehavior(cb->getObj(ObjectInstanceID(objid))).decompose(); + return CaptureObjectsBehavior(ai->cb->getObj(ObjectInstanceID(objid))).decompose(ai); } } diff --git a/AI/Nullkiller/Goals/CaptureObject.h b/AI/Nullkiller/Goals/CaptureObject.h index 2b3c339d6..bda5669af 100644 --- a/AI/Nullkiller/Goals/CaptureObject.h +++ b/AI/Nullkiller/Goals/CaptureObject.h @@ -35,7 +35,7 @@ namespace Goals } bool operator==(const CaptureObject & other) const override; - Goals::TGoalVec decompose() const override; + Goals::TGoalVec decompose(const Nullkiller * ai) const override; std::string toString() const override; bool hasHash() const override { return true; } uint64_t getHash() const override; diff --git a/AI/Nullkiller/Goals/CompleteQuest.cpp b/AI/Nullkiller/Goals/CompleteQuest.cpp index bdea43a27..4a80dffc9 100644 --- a/AI/Nullkiller/Goals/CompleteQuest.cpp +++ b/AI/Nullkiller/Goals/CompleteQuest.cpp @@ -29,36 +29,36 @@ std::string CompleteQuest::toString() const return "Complete quest " + questToString(); } -TGoalVec CompleteQuest::decompose() const +TGoalVec CompleteQuest::decompose(const Nullkiller * ai) const { if(isKeyMaster(q)) { - return missionKeymaster(); + return missionKeymaster(ai); } logAi->debug("Trying to realize quest: %s", questToString()); if(!q.quest->mission.artifacts.empty()) - return missionArt(); + return missionArt(ai); if(!q.quest->mission.heroes.empty()) - return missionHero(); + return missionHero(ai); if(!q.quest->mission.creatures.empty()) - return missionArmy(); + return missionArmy(ai); if(q.quest->mission.resources.nonZero()) - return missionResources(); + return missionResources(ai); if(q.quest->killTarget != ObjectInstanceID::NONE) - return missionDestroyObj(); + return missionDestroyObj(ai); for(auto & s : q.quest->mission.primary) if(s) - return missionIncreasePrimaryStat(); + return missionIncreasePrimaryStat(ai); if(q.quest->mission.heroLevel > 0) - return missionLevel(); + return missionLevel(ai); return TGoalVec(); } @@ -103,21 +103,21 @@ std::string CompleteQuest::questToString() const return ms.toString(); } -TGoalVec CompleteQuest::tryCompleteQuest() const +TGoalVec CompleteQuest::tryCompleteQuest(const Nullkiller * ai) const { - auto paths = ai->nullkiller->pathfinder->getPathInfo(q.obj->visitablePos()); + auto paths = ai->pathfinder->getPathInfo(q.obj->visitablePos()); vstd::erase_if(paths, [&](const AIPath & path) -> bool { return !q.quest->checkQuest(path.targetHero); }); - return CaptureObjectsBehavior::getVisitGoals(paths, ai->nullkiller.get(), q.obj); + return CaptureObjectsBehavior::getVisitGoals(paths, ai, q.obj); } -TGoalVec CompleteQuest::missionArt() const +TGoalVec CompleteQuest::missionArt(const Nullkiller * ai) const { - TGoalVec solutions = tryCompleteQuest(); + TGoalVec solutions = tryCompleteQuest(ai); if(!solutions.empty()) return solutions; @@ -132,9 +132,9 @@ TGoalVec CompleteQuest::missionArt() const return solutions; } -TGoalVec CompleteQuest::missionHero() const +TGoalVec CompleteQuest::missionHero(const Nullkiller * ai) const { - TGoalVec solutions = tryCompleteQuest(); + TGoalVec solutions = tryCompleteQuest(ai); if(solutions.empty()) { @@ -145,43 +145,43 @@ TGoalVec CompleteQuest::missionHero() const return solutions; } -TGoalVec CompleteQuest::missionArmy() const +TGoalVec CompleteQuest::missionArmy(const Nullkiller * ai) const { - auto paths = ai->nullkiller->pathfinder->getPathInfo(q.obj->visitablePos()); + auto paths = ai->pathfinder->getPathInfo(q.obj->visitablePos()); vstd::erase_if(paths, [&](const AIPath & path) -> bool { return !CQuest::checkMissionArmy(q.quest, path.heroArmy); }); - return CaptureObjectsBehavior::getVisitGoals(paths, ai->nullkiller.get(), q.obj); + return CaptureObjectsBehavior::getVisitGoals(paths, ai, q.obj); } -TGoalVec CompleteQuest::missionIncreasePrimaryStat() const +TGoalVec CompleteQuest::missionIncreasePrimaryStat(const Nullkiller * ai) const { - return tryCompleteQuest(); + return tryCompleteQuest(ai); } -TGoalVec CompleteQuest::missionLevel() const +TGoalVec CompleteQuest::missionLevel(const Nullkiller * ai) const { - return tryCompleteQuest(); + return tryCompleteQuest(ai); } -TGoalVec CompleteQuest::missionKeymaster() const +TGoalVec CompleteQuest::missionKeymaster(const Nullkiller * ai) const { - if(isObjectPassable(q.obj)) + if(isObjectPassable(ai, q.obj)) { - return CaptureObjectsBehavior(q.obj).decompose(); + return CaptureObjectsBehavior(q.obj).decompose(ai); } else { - return CaptureObjectsBehavior().ofType(Obj::KEYMASTER, q.obj->subID).decompose(); + return CaptureObjectsBehavior().ofType(Obj::KEYMASTER, q.obj->subID).decompose(ai); } } -TGoalVec CompleteQuest::missionResources() const +TGoalVec CompleteQuest::missionResources(const Nullkiller * ai) const { - TGoalVec solutions = tryCompleteQuest(); + TGoalVec solutions = tryCompleteQuest(ai); /*auto heroes = cb->getHeroesInfo(); //TODO: choose best / free hero from among many possibilities? @@ -208,14 +208,14 @@ TGoalVec CompleteQuest::missionResources() const return solutions; } -TGoalVec CompleteQuest::missionDestroyObj() const +TGoalVec CompleteQuest::missionDestroyObj(const Nullkiller * ai) const { - auto obj = cb->getObj(q.quest->killTarget); + auto obj = ai->cb->getObj(q.quest->killTarget); if(!obj) - return CaptureObjectsBehavior(q.obj).decompose(); + return CaptureObjectsBehavior(q.obj).decompose(ai); - auto relations = cb->getPlayerRelations(ai->playerID, obj->tempOwner); + auto relations = ai->cb->getPlayerRelations(ai->playerID, obj->tempOwner); //if(relations == PlayerRelations::SAME_PLAYER) //{ @@ -226,7 +226,7 @@ TGoalVec CompleteQuest::missionDestroyObj() const //else if(relations == PlayerRelations::ENEMIES) { - return CaptureObjectsBehavior(obj).decompose(); + return CaptureObjectsBehavior(obj).decompose(ai); } return TGoalVec(); diff --git a/AI/Nullkiller/Goals/CompleteQuest.h b/AI/Nullkiller/Goals/CompleteQuest.h index 57b9fb236..4ba6003ac 100644 --- a/AI/Nullkiller/Goals/CompleteQuest.h +++ b/AI/Nullkiller/Goals/CompleteQuest.h @@ -29,7 +29,7 @@ namespace Goals { } - Goals::TGoalVec decompose() const override; + Goals::TGoalVec decompose(const Nullkiller * ai) const override; std::string toString() const override; bool hasHash() const override { return true; } uint64_t getHash() const override; @@ -37,15 +37,15 @@ namespace Goals bool operator==(const CompleteQuest & other) const override; private: - TGoalVec tryCompleteQuest() const; - TGoalVec missionArt() const; - TGoalVec missionHero() const; - TGoalVec missionArmy() const; - TGoalVec missionResources() const; - TGoalVec missionDestroyObj() const; - TGoalVec missionIncreasePrimaryStat() const; - TGoalVec missionLevel() const; - TGoalVec missionKeymaster() const; + TGoalVec tryCompleteQuest(const Nullkiller * ai) const; + TGoalVec missionArt(const Nullkiller * ai) const; + TGoalVec missionHero(const Nullkiller * ai) const; + TGoalVec missionArmy(const Nullkiller * ai) const; + TGoalVec missionResources(const Nullkiller * ai) const; + TGoalVec missionDestroyObj(const Nullkiller * ai) const; + TGoalVec missionIncreasePrimaryStat(const Nullkiller * ai) const; + TGoalVec missionLevel(const Nullkiller * ai) const; + TGoalVec missionKeymaster(const Nullkiller * ai) const; std::string questToString() const; }; } diff --git a/AI/Nullkiller/Goals/Composition.cpp b/AI/Nullkiller/Goals/Composition.cpp index aff59aa7b..beb8275cf 100644 --- a/AI/Nullkiller/Goals/Composition.cpp +++ b/AI/Nullkiller/Goals/Composition.cpp @@ -59,7 +59,7 @@ void Composition::accept(AIGateway * ai) } } -TGoalVec Composition::decompose() const +TGoalVec Composition::decompose(const Nullkiller * ai) const { TGoalVec result; diff --git a/AI/Nullkiller/Goals/Composition.h b/AI/Nullkiller/Goals/Composition.h index a45d1327a..08db692a0 100644 --- a/AI/Nullkiller/Goals/Composition.h +++ b/AI/Nullkiller/Goals/Composition.h @@ -32,7 +32,7 @@ namespace Goals Composition & addNext(const AbstractGoal & goal); Composition & addNext(TSubgoal goal); Composition & addNextSequence(const TGoalVec & taskSequence); - TGoalVec decompose() const override; + TGoalVec decompose(const Nullkiller * ai) const override; bool isElementar() const override; int getHeroExchangeCount() const override; }; diff --git a/AI/Nullkiller/Goals/ExecuteHeroChain.cpp b/AI/Nullkiller/Goals/ExecuteHeroChain.cpp index 85ecac1b2..e8a2c3192 100644 --- a/AI/Nullkiller/Goals/ExecuteHeroChain.cpp +++ b/AI/Nullkiller/Goals/ExecuteHeroChain.cpp @@ -100,7 +100,7 @@ void ExecuteHeroChain::accept(AIGateway * ai) throw cannotFulfillGoalException("Path is nondeterministic."); } - node->specialAction->execute(hero); + node->specialAction->execute(ai, hero); if(!heroPtr.validAndSet()) { @@ -156,7 +156,7 @@ void ExecuteHeroChain::accept(AIGateway * ai) { try { - if(moveHeroToTile(hero, node->coord)) + if(moveHeroToTile(ai, hero, node->coord)) { continue; } @@ -224,9 +224,9 @@ std::string ExecuteHeroChain::toString() const return "ExecuteHeroChain " + targetName + " by " + chainPath.targetHero->getNameTranslated(); } -bool ExecuteHeroChain::moveHeroToTile(const CGHeroInstance * hero, const int3 & tile) +bool ExecuteHeroChain::moveHeroToTile(AIGateway * ai, const CGHeroInstance * hero, const int3 & tile) { - if(tile == hero->visitablePos() && cb->getVisitableObjs(hero->visitablePos()).size() < 2) + if(tile == hero->visitablePos() && ai->myCb->getVisitableObjs(hero->visitablePos()).size() < 2) { logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", hero->getNameTranslated(), tile.toString()); diff --git a/AI/Nullkiller/Goals/ExecuteHeroChain.h b/AI/Nullkiller/Goals/ExecuteHeroChain.h index a0e0ff39e..3018f8eec 100644 --- a/AI/Nullkiller/Goals/ExecuteHeroChain.h +++ b/AI/Nullkiller/Goals/ExecuteHeroChain.h @@ -27,7 +27,6 @@ namespace Goals ExecuteHeroChain(const AIPath & path, const CGObjectInstance * obj = nullptr); - void accept(AIGateway * ai) override; std::string toString() const override; bool operator==(const ExecuteHeroChain & other) const override; @@ -36,7 +35,7 @@ namespace Goals int getHeroExchangeCount() const override { return chainPath.exchangeCount; } private: - bool moveHeroToTile(const CGHeroInstance * hero, const int3 & tile); + bool moveHeroToTile(AIGateway * ai, const CGHeroInstance * hero, const int3 & tile); }; } diff --git a/AI/Nullkiller/Goals/Invalid.h b/AI/Nullkiller/Goals/Invalid.h index 5447b34b4..6207f1bb0 100644 --- a/AI/Nullkiller/Goals/Invalid.h +++ b/AI/Nullkiller/Goals/Invalid.h @@ -27,7 +27,7 @@ namespace Goals { priority = -1; } - TGoalVec decompose() const override + TGoalVec decompose(const Nullkiller * ai) const override { return TGoalVec(); } diff --git a/AI/Nullkiller/Markers/HeroExchange.cpp b/AI/Nullkiller/Markers/HeroExchange.cpp index cef89c1db..68c5e6f4f 100644 --- a/AI/Nullkiller/Markers/HeroExchange.cpp +++ b/AI/Nullkiller/Markers/HeroExchange.cpp @@ -29,9 +29,9 @@ std::string HeroExchange::toString() const return "Hero exchange for " +hero.get()->getObjectName() + " by " + exchangePath.toString(); } -uint64_t HeroExchange::getReinforcementArmyStrength() const +uint64_t HeroExchange::getReinforcementArmyStrength(const Nullkiller * ai) const { - uint64_t armyValue = ai->nullkiller->armyManager->howManyReinforcementsCanGet(hero.get(), exchangePath.heroArmy); + uint64_t armyValue = ai->armyManager->howManyReinforcementsCanGet(hero.get(), exchangePath.heroArmy); return armyValue; } diff --git a/AI/Nullkiller/Markers/HeroExchange.h b/AI/Nullkiller/Markers/HeroExchange.h index 95546716d..2c741b8f3 100644 --- a/AI/Nullkiller/Markers/HeroExchange.h +++ b/AI/Nullkiller/Markers/HeroExchange.h @@ -31,7 +31,7 @@ namespace Goals bool operator==(const HeroExchange & other) const override; std::string toString() const override; - uint64_t getReinforcementArmyStrength() const; + uint64_t getReinforcementArmyStrength(const Nullkiller * ai) const; }; } diff --git a/AI/Nullkiller/Pathfinding/AINodeStorage.cpp b/AI/Nullkiller/Pathfinding/AINodeStorage.cpp index d0226a985..8c2b6f01b 100644 --- a/AI/Nullkiller/Pathfinding/AINodeStorage.cpp +++ b/AI/Nullkiller/Pathfinding/AINodeStorage.cpp @@ -1389,7 +1389,7 @@ void AINodeStorage::fillChainInfo(const AIPathNode * node, AIPath & path, int pa { auto targetNode =node->theNodeBefore ? getAINode(node->theNodeBefore) : node; - pathNode.actionIsBlocked = !pathNode.specialAction->canAct(targetNode); + pathNode.actionIsBlocked = !pathNode.specialAction->canAct(ai, targetNode); } parentIndex = path.nodes.size(); diff --git a/AI/Nullkiller/Pathfinding/AIPathfinder.cpp b/AI/Nullkiller/Pathfinding/AIPathfinder.cpp index ec8b38a64..0d4623aca 100644 --- a/AI/Nullkiller/Pathfinding/AIPathfinder.cpp +++ b/AI/Nullkiller/Pathfinding/AIPathfinder.cpp @@ -17,6 +17,8 @@ namespace NKAI { +std::map> AIPathfinder::heroGraphs; + AIPathfinder::AIPathfinder(CPlayerSpecificInfoCallback * cb, Nullkiller * ai) :cb(cb), ai(ai) { diff --git a/AI/Nullkiller/Pathfinding/AIPathfinder.h b/AI/Nullkiller/Pathfinding/AIPathfinder.h index 69d3fa32e..15a277cad 100644 --- a/AI/Nullkiller/Pathfinding/AIPathfinder.h +++ b/AI/Nullkiller/Pathfinding/AIPathfinder.h @@ -40,7 +40,7 @@ private: std::shared_ptr storage; CPlayerSpecificInfoCallback * cb; Nullkiller * ai; - std::map> heroGraphs; + static std::map> heroGraphs; public: AIPathfinder(CPlayerSpecificInfoCallback * cb, Nullkiller * ai); diff --git a/AI/Nullkiller/Pathfinding/AIPathfinderConfig.cpp b/AI/Nullkiller/Pathfinding/AIPathfinderConfig.cpp index afd046bc8..ce9dd5b26 100644 --- a/AI/Nullkiller/Pathfinding/AIPathfinderConfig.cpp +++ b/AI/Nullkiller/Pathfinding/AIPathfinderConfig.cpp @@ -33,7 +33,7 @@ namespace AIPathfinding std::make_shared(nodeStorage, allowBypassObjects), std::make_shared(), std::make_shared(nodeStorage), - std::make_shared(cb, nodeStorage, allowBypassObjects) + std::make_shared(ai, cb, nodeStorage, allowBypassObjects) }; return rules; diff --git a/AI/Nullkiller/Pathfinding/Actions/AdventureSpellCastMovementActions.cpp b/AI/Nullkiller/Pathfinding/Actions/AdventureSpellCastMovementActions.cpp index 4da806986..cb0cfa102 100644 --- a/AI/Nullkiller/Pathfinding/Actions/AdventureSpellCastMovementActions.cpp +++ b/AI/Nullkiller/Pathfinding/Actions/AdventureSpellCastMovementActions.cpp @@ -49,14 +49,14 @@ namespace AIPathfinding dstNode->dayFlags = static_cast(dstNode->dayFlags | flagsToAdd); } - void AdventureCastAction::execute(const CGHeroInstance * hero) const + void AdventureCastAction::execute(AIGateway * ai, const CGHeroInstance * hero) const { assert(hero == this->hero); Goals::AdventureSpellCast(hero, spellToCast).accept(ai); } - bool AdventureCastAction::canAct(const AIPathNode * source) const + bool AdventureCastAction::canAct(const Nullkiller * ai, const AIPathNode * source) const { assert(hero == this->hero); diff --git a/AI/Nullkiller/Pathfinding/Actions/AdventureSpellCastMovementActions.h b/AI/Nullkiller/Pathfinding/Actions/AdventureSpellCastMovementActions.h index 7defcebf0..acbaf28fe 100644 --- a/AI/Nullkiller/Pathfinding/Actions/AdventureSpellCastMovementActions.h +++ b/AI/Nullkiller/Pathfinding/Actions/AdventureSpellCastMovementActions.h @@ -29,7 +29,7 @@ namespace AIPathfinding public: AdventureCastAction(SpellID spellToCast, const CGHeroInstance * hero, DayFlags flagsToAdd = DayFlags::NONE); - void execute(const CGHeroInstance * hero) const override; + void execute(AIGateway * ai, const CGHeroInstance * hero) const override; virtual void applyOnDestination( const CGHeroInstance * hero, @@ -38,7 +38,7 @@ namespace AIPathfinding AIPathNode * dstMode, const AIPathNode * srcNode) const override; - bool canAct(const AIPathNode * source) const override; + bool canAct(const Nullkiller * ai, const AIPathNode * source) const override; std::string toString() const override; }; diff --git a/AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp b/AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp index 33248df50..4a2851502 100644 --- a/AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp +++ b/AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp @@ -18,7 +18,7 @@ namespace NKAI namespace AIPathfinding { - void BattleAction::execute(const CGHeroInstance * hero) const + void BattleAction::execute(AIGateway * ai, const CGHeroInstance * hero) const { ai->moveHeroToTile(targetTile, hero); } diff --git a/AI/Nullkiller/Pathfinding/Actions/BattleAction.h b/AI/Nullkiller/Pathfinding/Actions/BattleAction.h index 838ba54c2..f4bad8ed0 100644 --- a/AI/Nullkiller/Pathfinding/Actions/BattleAction.h +++ b/AI/Nullkiller/Pathfinding/Actions/BattleAction.h @@ -28,7 +28,7 @@ namespace AIPathfinding { } - void execute(const CGHeroInstance * hero) const override; + void execute(AIGateway * ai, const CGHeroInstance * hero) const override; std::string toString() const override; }; diff --git a/AI/Nullkiller/Pathfinding/Actions/BoatActions.cpp b/AI/Nullkiller/Pathfinding/Actions/BoatActions.cpp index a7e86a681..d255dcb1e 100644 --- a/AI/Nullkiller/Pathfinding/Actions/BoatActions.cpp +++ b/AI/Nullkiller/Pathfinding/Actions/BoatActions.cpp @@ -22,12 +22,12 @@ namespace NKAI namespace AIPathfinding { - void BuildBoatAction::execute(const CGHeroInstance * hero) const + void BuildBoatAction::execute(AIGateway * ai, const CGHeroInstance * hero) const { return Goals::BuildBoat(shipyard).accept(ai); } - Goals::TSubgoal BuildBoatAction::decompose(const CGHeroInstance * hero) const + Goals::TSubgoal BuildBoatAction::decompose(const Nullkiller * ai, const CGHeroInstance * hero) const { if(cb->getPlayerRelations(ai->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES) { @@ -37,7 +37,7 @@ namespace AIPathfinding return Goals::sptr(Goals::Invalid()); } - bool BuildBoatAction::canAct(const CGHeroInstance * hero, const TResources & reservedResources) const + bool BuildBoatAction::canAct(const Nullkiller * ai, const CGHeroInstance * hero, const TResources & reservedResources) const { if(cb->getPlayerRelations(hero->tempOwner, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES) { @@ -63,16 +63,16 @@ namespace AIPathfinding return true; } - bool BuildBoatAction::canAct(const AIPathNode * source) const + bool BuildBoatAction::canAct(const Nullkiller * ai, const AIPathNode * source) const { - return canAct(source->actor->hero, source->actor->armyCost); + return canAct(ai, source->actor->hero, source->actor->armyCost); } - bool BuildBoatAction::canAct(const AIPathNodeInfo & source) const + bool BuildBoatAction::canAct(const Nullkiller * ai, const AIPathNodeInfo & source) const { TResources res; - return canAct(source.targetHero, res); + return canAct(ai, source.targetHero, res); } const CGObjectInstance * BuildBoatAction::targetObject() const @@ -90,7 +90,7 @@ namespace AIPathfinding return std::make_shared(ai->cb.get(), dynamic_cast(ai->cb->getObj(shipyard))); } - void SummonBoatAction::execute(const CGHeroInstance * hero) const + void SummonBoatAction::execute(AIGateway * ai, const CGHeroInstance * hero) const { Goals::AdventureSpellCast(hero, SpellID::SUMMON_BOAT).accept(ai); } @@ -116,7 +116,7 @@ namespace AIPathfinding return "Build Boat at " + shipyard->getObject()->visitablePos().toString(); } - bool SummonBoatAction::canAct(const AIPathNode * source) const + bool SummonBoatAction::canAct(const Nullkiller * ai, const AIPathNode * source) const { auto hero = source->actor->hero; diff --git a/AI/Nullkiller/Pathfinding/Actions/BoatActions.h b/AI/Nullkiller/Pathfinding/Actions/BoatActions.h index c8aa2c039..76857c3ca 100644 --- a/AI/Nullkiller/Pathfinding/Actions/BoatActions.h +++ b/AI/Nullkiller/Pathfinding/Actions/BoatActions.h @@ -25,7 +25,7 @@ namespace AIPathfinding class SummonBoatAction : public VirtualBoatAction { public: - void execute(const CGHeroInstance * hero) const override; + void execute(AIGateway * ai, const CGHeroInstance * hero) const override; virtual void applyOnDestination( const CGHeroInstance * hero, @@ -34,7 +34,7 @@ namespace AIPathfinding AIPathNode * dstMode, const AIPathNode * srcNode) const override; - bool canAct(const AIPathNode * source) const override; + bool canAct(const Nullkiller * ai, const AIPathNode * source) const override; const ChainActor * getActor(const ChainActor * sourceActor) const override; @@ -56,13 +56,13 @@ namespace AIPathfinding { } - bool canAct(const AIPathNode * source) const override; - bool canAct(const AIPathNodeInfo & source) const override; - bool canAct(const CGHeroInstance * hero, const TResources & reservedResources) const; + bool canAct(const Nullkiller * ai, const AIPathNode * source) const override; + bool canAct(const Nullkiller * ai, const AIPathNodeInfo & source) const override; + bool canAct(const Nullkiller * ai, const CGHeroInstance * hero, const TResources & reservedResources) const; - void execute(const CGHeroInstance * hero) const override; + void execute(AIGateway * ai, const CGHeroInstance * hero) const override; - Goals::TSubgoal decompose(const CGHeroInstance * hero) const override; + Goals::TSubgoal decompose(const Nullkiller * ai, const CGHeroInstance * hero) const override; const ChainActor * getActor(const ChainActor * sourceActor) const override; diff --git a/AI/Nullkiller/Pathfinding/Actions/BuyArmyAction.cpp b/AI/Nullkiller/Pathfinding/Actions/BuyArmyAction.cpp index a676ad5c1..f1fecf2d8 100644 --- a/AI/Nullkiller/Pathfinding/Actions/BuyArmyAction.cpp +++ b/AI/Nullkiller/Pathfinding/Actions/BuyArmyAction.cpp @@ -18,7 +18,7 @@ namespace NKAI namespace AIPathfinding { - void BuyArmyAction::execute(const CGHeroInstance * hero) const + void BuyArmyAction::execute(AIGateway * ai, const CGHeroInstance * hero) const { if(!hero->visitedTown) { diff --git a/AI/Nullkiller/Pathfinding/Actions/BuyArmyAction.h b/AI/Nullkiller/Pathfinding/Actions/BuyArmyAction.h index 8ec65e36b..da8d53e5b 100644 --- a/AI/Nullkiller/Pathfinding/Actions/BuyArmyAction.h +++ b/AI/Nullkiller/Pathfinding/Actions/BuyArmyAction.h @@ -21,12 +21,12 @@ namespace AIPathfinding private: public: - bool canAct(const AIPathNode * source) const override + bool canAct(const Nullkiller * ai, const AIPathNode * source) const override { return true; } - void execute(const CGHeroInstance * hero) const override; + void execute(AIGateway * ai, const CGHeroInstance * hero) const override; std::string toString() const override; }; } diff --git a/AI/Nullkiller/Pathfinding/Actions/QuestAction.cpp b/AI/Nullkiller/Pathfinding/Actions/QuestAction.cpp index 4880e623e..c4f71fc32 100644 --- a/AI/Nullkiller/Pathfinding/Actions/QuestAction.cpp +++ b/AI/Nullkiller/Pathfinding/Actions/QuestAction.cpp @@ -18,17 +18,17 @@ namespace NKAI namespace AIPathfinding { - bool QuestAction::canAct(const AIPathNode * node) const + bool QuestAction::canAct(const Nullkiller * ai, const AIPathNode * node) const { - return canAct(node->actor->hero); + return canAct(ai, node->actor->hero); } - bool QuestAction::canAct(const AIPathNodeInfo & node) const + bool QuestAction::canAct(const Nullkiller * ai, const AIPathNodeInfo & node) const { - return canAct(node.targetHero); + return canAct(ai, node.targetHero); } - bool QuestAction::canAct(const CGHeroInstance * hero) const + bool QuestAction::canAct(const Nullkiller * ai, const CGHeroInstance * hero) const { if(questInfo.obj->ID == Obj::BORDER_GATE || questInfo.obj->ID == Obj::BORDERGUARD) { @@ -39,12 +39,12 @@ namespace AIPathfinding || questInfo.quest->checkQuest(hero); } - Goals::TSubgoal QuestAction::decompose(const CGHeroInstance * hero) const + Goals::TSubgoal QuestAction::decompose(const Nullkiller * ai, const CGHeroInstance * hero) const { return Goals::sptr(Goals::CompleteQuest(questInfo)); } - void QuestAction::execute(const CGHeroInstance * hero) const + void QuestAction::execute(AIGateway * ai, const CGHeroInstance * hero) const { ai->moveHeroToTile(questInfo.obj->visitablePos(), hero); } diff --git a/AI/Nullkiller/Pathfinding/Actions/QuestAction.h b/AI/Nullkiller/Pathfinding/Actions/QuestAction.h index d86afac02..cc0dd59de 100644 --- a/AI/Nullkiller/Pathfinding/Actions/QuestAction.h +++ b/AI/Nullkiller/Pathfinding/Actions/QuestAction.h @@ -28,13 +28,13 @@ namespace AIPathfinding { } - bool canAct(const AIPathNode * node) const override; - bool canAct(const AIPathNodeInfo & node) const override; - bool canAct(const CGHeroInstance * hero) const; + bool canAct(const Nullkiller * ai, const AIPathNode * node) const override; + bool canAct(const Nullkiller * ai, const AIPathNodeInfo & node) const override; + bool canAct(const Nullkiller * ai, const CGHeroInstance * hero) const; - Goals::TSubgoal decompose(const CGHeroInstance * hero) const override; + Goals::TSubgoal decompose(const Nullkiller * ai, const CGHeroInstance * hero) const override; - void execute(const CGHeroInstance * hero) const override; + void execute(AIGateway * ai, const CGHeroInstance * hero) const override; std::string toString() const override; }; diff --git a/AI/Nullkiller/Pathfinding/Actions/SpecialAction.cpp b/AI/Nullkiller/Pathfinding/Actions/SpecialAction.cpp index 4fc1e4a45..8e1595b18 100644 --- a/AI/Nullkiller/Pathfinding/Actions/SpecialAction.cpp +++ b/AI/Nullkiller/Pathfinding/Actions/SpecialAction.cpp @@ -17,43 +17,43 @@ namespace NKAI { -Goals::TSubgoal SpecialAction::decompose(const CGHeroInstance * hero) const +Goals::TSubgoal SpecialAction::decompose(const Nullkiller * ai, const CGHeroInstance * hero) const { return Goals::sptr(Goals::Invalid()); } -void SpecialAction::execute(const CGHeroInstance * hero) const +void SpecialAction::execute(AIGateway * ai, const CGHeroInstance * hero) const { throw cannotFulfillGoalException("Can not execute " + toString()); } -bool CompositeAction::canAct(const AIPathNode * source) const +bool CompositeAction::canAct(const Nullkiller * ai, const AIPathNode * source) const { for(auto part : parts) { - if(!part->canAct(source)) return false; + if(!part->canAct(ai, source)) return false; } return true; } -Goals::TSubgoal CompositeAction::decompose(const CGHeroInstance * hero) const +Goals::TSubgoal CompositeAction::decompose(const Nullkiller * ai, const CGHeroInstance * hero) const { for(auto part : parts) { - auto goal = part->decompose(hero); + auto goal = part->decompose(ai, hero); if(!goal->invalid()) return goal; } - return SpecialAction::decompose(hero); + return SpecialAction::decompose(ai, hero); } -void CompositeAction::execute(const CGHeroInstance * hero) const +void CompositeAction::execute(AIGateway * ai, const CGHeroInstance * hero) const { for(auto part : parts) { - part->execute(hero); + part->execute(ai, hero); } } diff --git a/AI/Nullkiller/Pathfinding/Actions/SpecialAction.h b/AI/Nullkiller/Pathfinding/Actions/SpecialAction.h index 134bf8fe2..3d8e48fb1 100644 --- a/AI/Nullkiller/Pathfinding/Actions/SpecialAction.h +++ b/AI/Nullkiller/Pathfinding/Actions/SpecialAction.h @@ -30,19 +30,19 @@ class SpecialAction public: virtual ~SpecialAction() = default; - virtual bool canAct(const AIPathNode * source) const + virtual bool canAct(const Nullkiller * ai, const AIPathNode * source) const { return true; } - virtual bool canAct(const AIPathNodeInfo & source) const + virtual bool canAct(const Nullkiller * ai, const AIPathNodeInfo & source) const { return true; } - virtual Goals::TSubgoal decompose(const CGHeroInstance * hero) const; + virtual Goals::TSubgoal decompose(const Nullkiller * ai, const CGHeroInstance * hero) const; - virtual void execute(const CGHeroInstance * hero) const; + virtual void execute(AIGateway * ai, const CGHeroInstance * hero) const; virtual void applyOnDestination( const CGHeroInstance * hero, @@ -76,11 +76,11 @@ private: public: CompositeAction(std::vector> parts) : parts(parts) {} - bool canAct(const AIPathNode * source) const override; - void execute(const CGHeroInstance * hero) const override; + bool canAct(const Nullkiller * ai, const AIPathNode * source) const override; + void execute(AIGateway * ai, const CGHeroInstance * hero) const override; std::string toString() const override; const CGObjectInstance * targetObject() const override; - Goals::TSubgoal decompose(const CGHeroInstance * hero) const override; + Goals::TSubgoal decompose(const Nullkiller * ai, const CGHeroInstance * hero) const override; std::vector> getParts() const override { diff --git a/AI/Nullkiller/Pathfinding/Actions/TownPortalAction.cpp b/AI/Nullkiller/Pathfinding/Actions/TownPortalAction.cpp index e32a13231..f92a3a0b2 100644 --- a/AI/Nullkiller/Pathfinding/Actions/TownPortalAction.cpp +++ b/AI/Nullkiller/Pathfinding/Actions/TownPortalAction.cpp @@ -18,7 +18,7 @@ namespace NKAI using namespace AIPathfinding; -void TownPortalAction::execute(const CGHeroInstance * hero) const +void TownPortalAction::execute(AIGateway * ai, const CGHeroInstance * hero) const { auto goal = Goals::AdventureSpellCast(hero, SpellID::TOWN_PORTAL); diff --git a/AI/Nullkiller/Pathfinding/Actions/TownPortalAction.h b/AI/Nullkiller/Pathfinding/Actions/TownPortalAction.h index 05005156b..34c6c3c10 100644 --- a/AI/Nullkiller/Pathfinding/Actions/TownPortalAction.h +++ b/AI/Nullkiller/Pathfinding/Actions/TownPortalAction.h @@ -29,7 +29,7 @@ namespace AIPathfinding { } - void execute(const CGHeroInstance * hero) const override; + void execute(AIGateway * ai, const CGHeroInstance * hero) const override; std::string toString() const override; }; diff --git a/AI/Nullkiller/Pathfinding/ObjectGraph.cpp b/AI/Nullkiller/Pathfinding/ObjectGraph.cpp index 21d6b481d..6cb72b896 100644 --- a/AI/Nullkiller/Pathfinding/ObjectGraph.cpp +++ b/AI/Nullkiller/Pathfinding/ObjectGraph.cpp @@ -602,7 +602,7 @@ void GraphPaths::calculatePaths(const CGHeroInstance * targetHero, const Nullkil auto questAction = std::make_shared(questInfo); - if(!questAction->canAct(targetHero)) + if(!questAction->canAct(ai, targetHero)) { transitionAction = questAction; } @@ -762,7 +762,7 @@ void GraphPaths::addChainInfo(std::vector & paths, int3 tile, const CGHe if(n.specialAction) { - n.actionIsBlocked = !n.specialAction->canAct(n); + n.actionIsBlocked = !n.specialAction->canAct(ai, n); } for(auto & node : path.nodes) @@ -883,7 +883,7 @@ void GraphPaths::quickAddChainInfoWithBlocker(std::vector & paths, int3 if(n.specialAction) { - n.actionIsBlocked = !n.specialAction->canAct(n); + n.actionIsBlocked = !n.specialAction->canAct(ai, n); } auto blocker = ai->objectClusterizer->getBlocker(n); diff --git a/AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp b/AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp index ff0c6321d..d1ef6f4e9 100644 --- a/AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp +++ b/AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp @@ -177,7 +177,7 @@ namespace AIPathfinding const CGHeroInstance * hero = nodeStorage->getHero(source.node); if(vstd::contains(summonableVirtualBoats, hero) - && summonableVirtualBoats.at(hero)->canAct(nodeStorage->getAINode(source.node))) + && summonableVirtualBoats.at(hero)->canAct(ai, nodeStorage->getAINode(source.node))) { virtualBoat = summonableVirtualBoats.at(hero); } diff --git a/AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp b/AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp index 3b0e4f798..f2c0fc180 100644 --- a/AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp +++ b/AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp @@ -20,10 +20,11 @@ namespace NKAI namespace AIPathfinding { AIMovementAfterDestinationRule::AIMovementAfterDestinationRule( + const Nullkiller * ai, CPlayerSpecificInfoCallback * cb, std::shared_ptr nodeStorage, bool allowBypassObjects) - :cb(cb), nodeStorage(nodeStorage), allowBypassObjects(allowBypassObjects) + :ai(ai), cb(cb), nodeStorage(nodeStorage), allowBypassObjects(allowBypassObjects) { } @@ -171,7 +172,7 @@ namespace AIPathfinding return false; } - if(!questAction.canAct(destinationNode)) + if(!questAction.canAct(ai, destinationNode)) { if(!destinationNode->actor->allowUseResources) { diff --git a/AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.h b/AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.h index 35b91a45d..7442b0394 100644 --- a/AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.h +++ b/AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.h @@ -24,11 +24,13 @@ namespace AIPathfinding { private: CPlayerSpecificInfoCallback * cb; + const Nullkiller * ai; std::shared_ptr nodeStorage; bool allowBypassObjects; public: AIMovementAfterDestinationRule( + const Nullkiller * ai, CPlayerSpecificInfoCallback * cb, std::shared_ptr nodeStorage, bool allowBypassObjects);