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:
parent
2798dcd6c5
commit
642f3a3fa4
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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",
|
||||
|
@ -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:
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user