1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-19 21:10:12 +02:00

Nullkiller: fix a few freezes

This commit is contained in:
Andrii Danylchenko 2021-05-16 13:52:30 +03:00 committed by Andrii Danylchenko
parent 2798dcd6c5
commit 642f3a3fa4
7 changed files with 91 additions and 8 deletions

View File

@ -28,6 +28,17 @@ std::string CaptureObjectsBehavior::toString() const
return "Capture objects";
}
std::shared_ptr<const ISpecialAction> getFirstBlockedAction(const AIPath & path)
{
for(auto node : path.nodes)
{
if(node.specialAction && !node.specialAction->canAct(node.targetHero))
return node.specialAction;
}
return std::shared_ptr<const ISpecialAction>();
}
Goals::TGoalVec CaptureObjectsBehavior::getTasks()
{
Goals::TGoalVec tasks;
@ -65,6 +76,15 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
logAi->trace("Path found %s", path.toString());
#endif
if(getFirstBlockedAction(path))
{
#ifdef VCMI_TRACE_PATHFINDER
// TODO: decomposition?
logAi->trace("Ignore path. Action is blocked.");
#endif
continue;
}
if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
{
#ifdef VCMI_TRACE_PATHFINDER
@ -78,6 +98,10 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
auto hero = path.targetHero;
auto danger = path.getTotalDanger(hero);
if(danger == 0 && path.exchangeCount > 1)
continue;
auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);
#ifdef VCMI_TRACE_PATHFINDER
@ -146,7 +170,8 @@ bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const
const int3 pos = objInstance->visitablePos();
if(vstd::contains(ai->alreadyVisited, objInstance))
if(objInstance->ID != Obj::CREATURE_GENERATOR1 && vstd::contains(ai->alreadyVisited, objInstance)
|| obj->wasVisited(ai->playerID))
{
return false;
}

View File

@ -16,6 +16,7 @@
#include "../Goals/ExecuteHeroChain.h"
#include "../Goals/ExchangeSwapTownHeroes.h"
#include "lib/mapping/CMap.h" //for victory conditions
#include "lib/mapObjects/MapObjects.h" //for victory conditions
#include "lib/CPathfinder.h"
extern boost::thread_specific_ptr<CCallback> cb;
@ -78,7 +79,8 @@ bool needToRecruitHero(const CGTownInstance * startupTown)
|| obj->ID == Obj::WATER_WHEEL)
{
auto path = paths->getPathInfo(obj->visitablePos());
if(path->accessible == CGPathNode::BLOCKVIS && path->turns != 255)
if((path->accessible == CGPathNode::BLOCKVIS || path->accessible == CGPathNode::VISIT)
&& path->reachable())
{
return true;
}

View File

@ -331,6 +331,7 @@ void AINodeStorage::calculateHeroChain(
{
if(carrier->armyLoss < carrier->actor->armyValue
&& (carrier->action != CGPathNode::BATTLE || (carrier->actor->allowBattle && carrier->specialAction))
&& carrier->action != CGPathNode::BLOCKING_VISIT
&& other->armyLoss < other->actor->armyValue
&& carrier->actor->canExchange(other->actor))
{
@ -745,6 +746,7 @@ std::vector<AIPath> AINodeStorage::getChainInfo(const int3 & pos, bool isOnLand)
path.armyLoss = node.armyLoss;
path.targetObjectDanger = evaluateDanger(pos, path.targetHero);
path.chainMask = node.actor->chainMask;
path.exchangeCount = node.actor->actorExchangeCount;
fillChainInfo(&node, path, -1);

View File

@ -10,7 +10,7 @@
#pragma once
#undef VCMI_TRACE_PATHFINDER
#define VCMI_TRACE_PATHFINDER 1
#include "../../../lib/CPathfinder.h"
#include "../../../lib/mapObjects/CGHeroInstance.h"
@ -50,6 +50,7 @@ struct AIPath
const CGHeroInstance * targetHero;
const CCreatureSet * heroArmy;
uint64_t chainMask;
uint8_t exchangeCount;
AIPath();

View File

@ -18,6 +18,11 @@ struct AIPathNode;
class ISpecialAction
{
public:
virtual bool canAct(const CGHeroInstance * hero) const
{
return true;
}
virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const = 0;
virtual void applyOnDestination(

View File

@ -10,9 +10,28 @@
#include "StdInc.h"
#include "AIMovementAfterDestinationRule.h"
#include "../Actions/BattleAction.h"
#include "../../Goals/Invalid.h"
namespace AIPathfinding
{
class QuestAction : public ISpecialAction
{
public:
QuestAction(QuestInfo questInfo)
{
}
virtual bool canAct(const CGHeroInstance * hero) const override
{
return false;
}
virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const override
{
return Goals::sptr(Goals::Invalid());
}
};
AIMovementAfterDestinationRule::AIMovementAfterDestinationRule(
CPlayerSpecificInfoCallback * cb,
std::shared_ptr<AINodeStorage> nodeStorage)
@ -50,6 +69,23 @@ namespace AIPathfinding
destination.blocked = true;
}
if(destination.nodeObject->ID == Obj::QUEST_GUARD || destination.nodeObject->ID == Obj::BORDERGUARD)
{
auto questObj = dynamic_cast<const IQuestObject *>(destination.nodeObject);
auto nodeHero = pathfinderHelper->hero;
if(!destination.nodeObject->wasVisited(nodeHero->tempOwner)
|| !questObj->checkQuest(nodeHero))
{
nodeStorage->updateAINode(destination.node, [&](AIPathNode * node)
{
auto questInfo = QuestInfo(questObj->quest, destination.nodeObject, destination.coord);
node->specialAction.reset(new QuestAction(questInfo));
});
}
}
return;
}
@ -141,6 +177,12 @@ namespace AIPathfinding
vstd::amax(battleNode->danger, danger);
battleNode->specialAction = std::make_shared<BattleAction>(destination.coord);
if(source.nodeObject && isObjectRemovable(source.nodeObject))
{
battleNode->theNodeBefore = source.node;
}
#ifdef VCMI_TRACE_PATHFINDER
logAi->trace(
"Begin bypass guard at destination with danger %s while moving %s -> %s",

View File

@ -603,7 +603,7 @@ void VCAI::init(std::shared_ptr<CCallback> CB)
if(!fh)
fh = new FuzzyHelper();
if(playerID.getStr(false) == "blue")
if(playerID.getStr(false) == "red")
{
nullkiller.reset(new Nullkiller());
}
@ -2823,17 +2823,23 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
{
if(obj->tempOwner != h->tempOwner)
return true; //flag just in case
bool canRecruitCreatures = false;
const CGDwelling * d = dynamic_cast<const CGDwelling *>(obj);
for(auto level : d->creatures)
{
for(auto c : level.second)
{
if(h->getSlotFor(CreatureID(c)) != SlotID())
canRecruitCreatures = true;
if(level.first
&& h->getSlotFor(CreatureID(c)) != SlotID()
&& cb->getResourceAmount().canAfford(c.toCreature()->cost))
{
return true;
}
}
}
return canRecruitCreatures;
return false;
}
case Obj::HILL_FORT:
{