mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-27 21:49:10 +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";
|
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 CaptureObjectsBehavior::getTasks()
|
||||||
{
|
{
|
||||||
Goals::TGoalVec tasks;
|
Goals::TGoalVec tasks;
|
||||||
@ -65,6 +76,15 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
|
|||||||
logAi->trace("Path found %s", path.toString());
|
logAi->trace("Path found %s", path.toString());
|
||||||
#endif
|
#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))
|
if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
|
||||||
{
|
{
|
||||||
#ifdef VCMI_TRACE_PATHFINDER
|
#ifdef VCMI_TRACE_PATHFINDER
|
||||||
@ -78,6 +98,10 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
|
|||||||
|
|
||||||
auto hero = path.targetHero;
|
auto hero = path.targetHero;
|
||||||
auto danger = path.getTotalDanger(hero);
|
auto danger = path.getTotalDanger(hero);
|
||||||
|
|
||||||
|
if(danger == 0 && path.exchangeCount > 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);
|
auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);
|
||||||
|
|
||||||
#ifdef VCMI_TRACE_PATHFINDER
|
#ifdef VCMI_TRACE_PATHFINDER
|
||||||
@ -146,7 +170,8 @@ bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const
|
|||||||
|
|
||||||
const int3 pos = objInstance->visitablePos();
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "../Goals/ExecuteHeroChain.h"
|
#include "../Goals/ExecuteHeroChain.h"
|
||||||
#include "../Goals/ExchangeSwapTownHeroes.h"
|
#include "../Goals/ExchangeSwapTownHeroes.h"
|
||||||
#include "lib/mapping/CMap.h" //for victory conditions
|
#include "lib/mapping/CMap.h" //for victory conditions
|
||||||
|
#include "lib/mapObjects/MapObjects.h" //for victory conditions
|
||||||
#include "lib/CPathfinder.h"
|
#include "lib/CPathfinder.h"
|
||||||
|
|
||||||
extern boost::thread_specific_ptr<CCallback> cb;
|
extern boost::thread_specific_ptr<CCallback> cb;
|
||||||
@ -78,7 +79,8 @@ bool needToRecruitHero(const CGTownInstance * startupTown)
|
|||||||
|| obj->ID == Obj::WATER_WHEEL)
|
|| obj->ID == Obj::WATER_WHEEL)
|
||||||
{
|
{
|
||||||
auto path = paths->getPathInfo(obj->visitablePos());
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -331,6 +331,7 @@ void AINodeStorage::calculateHeroChain(
|
|||||||
{
|
{
|
||||||
if(carrier->armyLoss < carrier->actor->armyValue
|
if(carrier->armyLoss < carrier->actor->armyValue
|
||||||
&& (carrier->action != CGPathNode::BATTLE || (carrier->actor->allowBattle && carrier->specialAction))
|
&& (carrier->action != CGPathNode::BATTLE || (carrier->actor->allowBattle && carrier->specialAction))
|
||||||
|
&& carrier->action != CGPathNode::BLOCKING_VISIT
|
||||||
&& other->armyLoss < other->actor->armyValue
|
&& other->armyLoss < other->actor->armyValue
|
||||||
&& carrier->actor->canExchange(other->actor))
|
&& carrier->actor->canExchange(other->actor))
|
||||||
{
|
{
|
||||||
@ -745,6 +746,7 @@ std::vector<AIPath> AINodeStorage::getChainInfo(const int3 & pos, bool isOnLand)
|
|||||||
path.armyLoss = node.armyLoss;
|
path.armyLoss = node.armyLoss;
|
||||||
path.targetObjectDanger = evaluateDanger(pos, path.targetHero);
|
path.targetObjectDanger = evaluateDanger(pos, path.targetHero);
|
||||||
path.chainMask = node.actor->chainMask;
|
path.chainMask = node.actor->chainMask;
|
||||||
|
path.exchangeCount = node.actor->actorExchangeCount;
|
||||||
|
|
||||||
fillChainInfo(&node, path, -1);
|
fillChainInfo(&node, path, -1);
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#undef VCMI_TRACE_PATHFINDER
|
#define VCMI_TRACE_PATHFINDER 1
|
||||||
|
|
||||||
#include "../../../lib/CPathfinder.h"
|
#include "../../../lib/CPathfinder.h"
|
||||||
#include "../../../lib/mapObjects/CGHeroInstance.h"
|
#include "../../../lib/mapObjects/CGHeroInstance.h"
|
||||||
@ -50,6 +50,7 @@ struct AIPath
|
|||||||
const CGHeroInstance * targetHero;
|
const CGHeroInstance * targetHero;
|
||||||
const CCreatureSet * heroArmy;
|
const CCreatureSet * heroArmy;
|
||||||
uint64_t chainMask;
|
uint64_t chainMask;
|
||||||
|
uint8_t exchangeCount;
|
||||||
|
|
||||||
AIPath();
|
AIPath();
|
||||||
|
|
||||||
|
@ -18,6 +18,11 @@ struct AIPathNode;
|
|||||||
class ISpecialAction
|
class ISpecialAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual bool canAct(const CGHeroInstance * hero) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const = 0;
|
virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const = 0;
|
||||||
|
|
||||||
virtual void applyOnDestination(
|
virtual void applyOnDestination(
|
||||||
|
@ -10,9 +10,28 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "AIMovementAfterDestinationRule.h"
|
#include "AIMovementAfterDestinationRule.h"
|
||||||
#include "../Actions/BattleAction.h"
|
#include "../Actions/BattleAction.h"
|
||||||
|
#include "../../Goals/Invalid.h"
|
||||||
|
|
||||||
namespace AIPathfinding
|
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(
|
AIMovementAfterDestinationRule::AIMovementAfterDestinationRule(
|
||||||
CPlayerSpecificInfoCallback * cb,
|
CPlayerSpecificInfoCallback * cb,
|
||||||
std::shared_ptr<AINodeStorage> nodeStorage)
|
std::shared_ptr<AINodeStorage> nodeStorage)
|
||||||
@ -50,6 +69,23 @@ namespace AIPathfinding
|
|||||||
destination.blocked = true;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,6 +177,12 @@ namespace AIPathfinding
|
|||||||
vstd::amax(battleNode->danger, danger);
|
vstd::amax(battleNode->danger, danger);
|
||||||
|
|
||||||
battleNode->specialAction = std::make_shared<BattleAction>(destination.coord);
|
battleNode->specialAction = std::make_shared<BattleAction>(destination.coord);
|
||||||
|
|
||||||
|
if(source.nodeObject && isObjectRemovable(source.nodeObject))
|
||||||
|
{
|
||||||
|
battleNode->theNodeBefore = source.node;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef VCMI_TRACE_PATHFINDER
|
#ifdef VCMI_TRACE_PATHFINDER
|
||||||
logAi->trace(
|
logAi->trace(
|
||||||
"Begin bypass guard at destination with danger %s while moving %s -> %s",
|
"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)
|
if(!fh)
|
||||||
fh = new FuzzyHelper();
|
fh = new FuzzyHelper();
|
||||||
|
|
||||||
if(playerID.getStr(false) == "blue")
|
if(playerID.getStr(false) == "red")
|
||||||
{
|
{
|
||||||
nullkiller.reset(new Nullkiller());
|
nullkiller.reset(new Nullkiller());
|
||||||
}
|
}
|
||||||
@ -2823,17 +2823,23 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
|
|||||||
{
|
{
|
||||||
if(obj->tempOwner != h->tempOwner)
|
if(obj->tempOwner != h->tempOwner)
|
||||||
return true; //flag just in case
|
return true; //flag just in case
|
||||||
bool canRecruitCreatures = false;
|
|
||||||
const CGDwelling * d = dynamic_cast<const CGDwelling *>(obj);
|
const CGDwelling * d = dynamic_cast<const CGDwelling *>(obj);
|
||||||
|
|
||||||
for(auto level : d->creatures)
|
for(auto level : d->creatures)
|
||||||
{
|
{
|
||||||
for(auto c : level.second)
|
for(auto c : level.second)
|
||||||
{
|
{
|
||||||
if(h->getSlotFor(CreatureID(c)) != SlotID())
|
if(level.first
|
||||||
canRecruitCreatures = true;
|
&& h->getSlotFor(CreatureID(c)) != SlotID()
|
||||||
|
&& cb->getResourceAmount().canAfford(c.toCreature()->cost))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return canRecruitCreatures;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
case Obj::HILL_FORT:
|
case Obj::HILL_FORT:
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user