mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-06 09:09:40 +02:00
AI: extract pathfinding special actions and rules to separate files
This commit is contained in:
154
AI/VCAI/Pathfinding/Rules/AILayerTransitionRule.cpp
Normal file
154
AI/VCAI/Pathfinding/Rules/AILayerTransitionRule.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* AILayerTransitionRule.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "AILayerTransitionRule.h"
|
||||
|
||||
namespace AIPathfinding
|
||||
{
|
||||
AILayerTransitionRule::AILayerTransitionRule(CPlayerSpecificInfoCallback * cb, VCAI * ai, std::shared_ptr<AINodeStorage> nodeStorage)
|
||||
:cb(cb), ai(ai), nodeStorage(nodeStorage)
|
||||
{
|
||||
setup();
|
||||
}
|
||||
|
||||
void AILayerTransitionRule::process(
|
||||
const PathNodeInfo & source,
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathfinderConfig * pathfinderConfig,
|
||||
CPathfinderHelper * pathfinderHelper) const
|
||||
{
|
||||
LayerTransitionRule::process(source, destination, pathfinderConfig, pathfinderHelper);
|
||||
|
||||
if(!destination.blocked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(source.node->layer == EPathfindingLayer::LAND && destination.node->layer == EPathfindingLayer::SAIL)
|
||||
{
|
||||
std::shared_ptr<const VirtualBoatAction> virtualBoat = findVirtualBoat(destination, source);
|
||||
|
||||
if(virtualBoat && tryEmbarkVirtualBoat(destination, source, virtualBoat))
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace("Embarking to virtual boat while moving %s -> %s!", source.coord.toString(), destination.coord.toString());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AILayerTransitionRule::setup()
|
||||
{
|
||||
std::vector<const IShipyard *> shipyards;
|
||||
|
||||
for(const CGTownInstance * t : cb->getTownsInfo())
|
||||
{
|
||||
if(t->hasBuilt(BuildingID::SHIPYARD))
|
||||
shipyards.push_back(t);
|
||||
}
|
||||
|
||||
for(const CGObjectInstance * obj : ai->visitableObjs)
|
||||
{
|
||||
if(obj->ID != Obj::TOWN) //towns were handled in the previous loop
|
||||
{
|
||||
if(const IShipyard * shipyard = IShipyard::castFrom(obj))
|
||||
shipyards.push_back(shipyard);
|
||||
}
|
||||
}
|
||||
|
||||
for(const IShipyard * shipyard : shipyards)
|
||||
{
|
||||
if(shipyard->shipyardStatus() == IShipyard::GOOD)
|
||||
{
|
||||
int3 boatLocation = shipyard->bestLocation();
|
||||
virtualBoats[boatLocation] = std::make_shared<BuildBoatAction>(shipyard);
|
||||
logAi->debug("Virtual boat added at %s", boatLocation.toString());
|
||||
}
|
||||
}
|
||||
|
||||
auto hero = nodeStorage->getHero();
|
||||
auto summonBoatSpell = SpellID(SpellID::SUMMON_BOAT).toSpell();
|
||||
|
||||
if(hero->canCastThisSpell(summonBoatSpell)
|
||||
&& hero->getSpellSchoolLevel(summonBoatSpell) >= SecSkillLevel::ADVANCED)
|
||||
{
|
||||
// TODO: For lower school level we might need to check the existance of some boat
|
||||
summonableVirtualBoat.reset(new SummonBoatAction());
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const VirtualBoatAction> AILayerTransitionRule::findVirtualBoat(
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathNodeInfo & source) const
|
||||
{
|
||||
std::shared_ptr<const VirtualBoatAction> virtualBoat;
|
||||
|
||||
if(vstd::contains(virtualBoats, destination.coord))
|
||||
{
|
||||
virtualBoat = virtualBoats.at(destination.coord);
|
||||
}
|
||||
else if(
|
||||
summonableVirtualBoat
|
||||
&& summonableVirtualBoat->isAffordableBy(nodeStorage->getHero(), nodeStorage->getAINode(source.node)))
|
||||
{
|
||||
virtualBoat = summonableVirtualBoat;
|
||||
}
|
||||
|
||||
return virtualBoat;
|
||||
}
|
||||
|
||||
bool AILayerTransitionRule::tryEmbarkVirtualBoat(
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathNodeInfo & source,
|
||||
std::shared_ptr<const VirtualBoatAction> virtualBoat) const
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
nodeStorage->updateAINode(destination.node, [&](AIPathNode * node)
|
||||
{
|
||||
auto boatNodeOptional = nodeStorage->getOrCreateNode(
|
||||
node->coord,
|
||||
node->layer,
|
||||
node->chainMask | virtualBoat->getSpecialChain());
|
||||
|
||||
if(boatNodeOptional)
|
||||
{
|
||||
AIPathNode * boatNode = boatNodeOptional.get();
|
||||
|
||||
if(boatNode->action == CGPathNode::UNKNOWN)
|
||||
{
|
||||
boatNode->specialAction = virtualBoat;
|
||||
destination.blocked = false;
|
||||
destination.action = CGPathNode::ENodeAction::EMBARK;
|
||||
destination.node = boatNode;
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace(
|
||||
"Special transition node already allocated. Blocked moving %s -> %s",
|
||||
source.coord.toString(),
|
||||
destination.coord.toString());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logAi->debug(
|
||||
"Can not allocate special transition node while moving %s -> %s",
|
||||
source.coord.toString(),
|
||||
destination.coord.toString());
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
52
AI/VCAI/Pathfinding/Rules/AILayerTransitionRule.h
Normal file
52
AI/VCAI/Pathfinding/Rules/AILayerTransitionRule.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* AILayerTransitionRule.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../AINodeStorage.h"
|
||||
#include "../../VCAI.h"
|
||||
#include "../Actions/BoatActions.h"
|
||||
#include "../../../../CCallback.h"
|
||||
#include "../../../../lib/mapping/CMap.h"
|
||||
#include "../../../../lib/mapObjects/MapObjects.h"
|
||||
|
||||
namespace AIPathfinding
|
||||
{
|
||||
class AILayerTransitionRule : public LayerTransitionRule
|
||||
{
|
||||
private:
|
||||
CPlayerSpecificInfoCallback * cb;
|
||||
VCAI * ai;
|
||||
std::map<int3, std::shared_ptr<const BuildBoatAction>> virtualBoats;
|
||||
std::shared_ptr<AINodeStorage> nodeStorage;
|
||||
std::shared_ptr<const SummonBoatAction> summonableVirtualBoat;
|
||||
|
||||
public:
|
||||
AILayerTransitionRule(CPlayerSpecificInfoCallback * cb, VCAI * ai, std::shared_ptr<AINodeStorage> nodeStorage);
|
||||
|
||||
virtual void process(
|
||||
const PathNodeInfo & source,
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathfinderConfig * pathfinderConfig,
|
||||
CPathfinderHelper * pathfinderHelper) const override;
|
||||
|
||||
private:
|
||||
void setup();
|
||||
|
||||
std::shared_ptr<const VirtualBoatAction> findVirtualBoat(
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathNodeInfo & source) const;
|
||||
|
||||
bool tryEmbarkVirtualBoat(
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathNodeInfo & source,
|
||||
std::shared_ptr<const VirtualBoatAction> virtualBoat) const;
|
||||
};
|
||||
}
|
||||
148
AI/VCAI/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp
Normal file
148
AI/VCAI/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* AIMovementAfterDestinationRule.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "AIMovementAfterDestinationRule.h"
|
||||
#include "../Actions/BattleAction.h"
|
||||
|
||||
namespace AIPathfinding
|
||||
{
|
||||
AIMovementAfterDestinationRule::AIMovementAfterDestinationRule(
|
||||
CPlayerSpecificInfoCallback * cb,
|
||||
std::shared_ptr<AINodeStorage> nodeStorage)
|
||||
:cb(cb), nodeStorage(nodeStorage)
|
||||
{
|
||||
}
|
||||
|
||||
void AIMovementAfterDestinationRule::process(
|
||||
const PathNodeInfo & source,
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathfinderConfig * pathfinderConfig,
|
||||
CPathfinderHelper * pathfinderHelper) const
|
||||
{
|
||||
if(nodeStorage->hasBetterChain(source, destination))
|
||||
{
|
||||
destination.blocked = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto blocker = getBlockingReason(source, destination, pathfinderConfig, pathfinderHelper);
|
||||
|
||||
if(blocker == BlockingReason::NONE)
|
||||
return;
|
||||
|
||||
if(blocker == BlockingReason::DESTINATION_BLOCKVIS && destination.nodeObject)
|
||||
{
|
||||
auto objID = destination.nodeObject->ID;
|
||||
auto enemyHero = objID == Obj::HERO && destination.objectRelations == PlayerRelations::ENEMIES;
|
||||
|
||||
if(!enemyHero && !isObjectRemovable(destination.nodeObject))
|
||||
{
|
||||
destination.blocked = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(blocker == BlockingReason::DESTINATION_VISIT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(blocker == BlockingReason::DESTINATION_GUARDED)
|
||||
{
|
||||
auto srcGuardians = cb->getGuardingCreatures(source.coord);
|
||||
auto destGuardians = cb->getGuardingCreatures(destination.coord);
|
||||
|
||||
if(destGuardians.empty())
|
||||
{
|
||||
destination.blocked = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
vstd::erase_if(destGuardians, [&](const CGObjectInstance * destGuard) -> bool
|
||||
{
|
||||
return vstd::contains(srcGuardians, destGuard);
|
||||
});
|
||||
|
||||
auto guardsAlreadyBypassed = destGuardians.empty() && srcGuardians.size();
|
||||
if(guardsAlreadyBypassed && nodeStorage->isBattleNode(source.node))
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace(
|
||||
"Bypass guard at destination while moving %s -> %s",
|
||||
source.coord.toString(),
|
||||
destination.coord.toString());
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const AIPathNode * destNode = nodeStorage->getAINode(destination.node);
|
||||
auto battleNodeOptional = nodeStorage->getOrCreateNode(
|
||||
destination.coord,
|
||||
destination.node->layer,
|
||||
destNode->chainMask | AINodeStorage::BATTLE_CHAIN);
|
||||
|
||||
if(!battleNodeOptional)
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace(
|
||||
"Can not allocate battle node while moving %s -> %s",
|
||||
source.coord.toString(),
|
||||
destination.coord.toString());
|
||||
#endif
|
||||
|
||||
destination.blocked = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
AIPathNode * battleNode = battleNodeOptional.get();
|
||||
|
||||
if(battleNode->locked)
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace(
|
||||
"Block bypass guard at destination while moving %s -> %s",
|
||||
source.coord.toString(),
|
||||
destination.coord.toString());
|
||||
#endif
|
||||
destination.blocked = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto hero = nodeStorage->getHero();
|
||||
auto danger = evaluateDanger(destination.coord, hero);
|
||||
|
||||
destination.node = battleNode;
|
||||
nodeStorage->commit(destination, source);
|
||||
|
||||
if(battleNode->danger < danger)
|
||||
{
|
||||
battleNode->danger = danger;
|
||||
}
|
||||
|
||||
battleNode->specialAction = std::make_shared<BattleAction>(destination.coord);
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace(
|
||||
"Begin bypass guard at destination with danger %s while moving %s -> %s",
|
||||
std::to_string(danger),
|
||||
source.coord.toString(),
|
||||
destination.coord.toString());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
destination.blocked = true;
|
||||
}
|
||||
}
|
||||
36
AI/VCAI/Pathfinding/Rules/AIMovementAfterDestinationRule.h
Normal file
36
AI/VCAI/Pathfinding/Rules/AIMovementAfterDestinationRule.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* AIMovementAfterDestinationRule.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../AINodeStorage.h"
|
||||
#include "../../VCAI.h"
|
||||
#include "../../../../CCallback.h"
|
||||
#include "../../../../lib/mapping/CMap.h"
|
||||
#include "../../../../lib/mapObjects/MapObjects.h"
|
||||
|
||||
namespace AIPathfinding
|
||||
{
|
||||
class AIMovementAfterDestinationRule : public MovementAfterDestinationRule
|
||||
{
|
||||
private:
|
||||
CPlayerSpecificInfoCallback * cb;
|
||||
std::shared_ptr<AINodeStorage> nodeStorage;
|
||||
|
||||
public:
|
||||
AIMovementAfterDestinationRule(CPlayerSpecificInfoCallback * cb, std::shared_ptr<AINodeStorage> nodeStorage);
|
||||
|
||||
virtual void process(
|
||||
const PathNodeInfo & source,
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathfinderConfig * pathfinderConfig,
|
||||
CPathfinderHelper * pathfinderHelper) const override;
|
||||
};
|
||||
}
|
||||
51
AI/VCAI/Pathfinding/Rules/AIMovementToDestinationRule.cpp
Normal file
51
AI/VCAI/Pathfinding/Rules/AIMovementToDestinationRule.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* AIMovementToDestinationRule.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "AIMovementToDestinationRule.h"
|
||||
|
||||
namespace AIPathfinding
|
||||
{
|
||||
AIMovementToDestinationRule::AIMovementToDestinationRule(std::shared_ptr<AINodeStorage> nodeStorage)
|
||||
: nodeStorage(nodeStorage)
|
||||
{
|
||||
}
|
||||
|
||||
void AIMovementToDestinationRule::process(
|
||||
const PathNodeInfo & source,
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathfinderConfig * pathfinderConfig,
|
||||
CPathfinderHelper * pathfinderHelper) const
|
||||
{
|
||||
auto blocker = getBlockingReason(source, destination, pathfinderConfig, pathfinderHelper);
|
||||
|
||||
if(blocker == BlockingReason::NONE)
|
||||
return;
|
||||
|
||||
if(blocker == BlockingReason::DESTINATION_BLOCKED
|
||||
&& destination.action == CGPathNode::EMBARK
|
||||
&& nodeStorage->getAINode(destination.node)->specialAction)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(blocker == BlockingReason::SOURCE_GUARDED && nodeStorage->isBattleNode(source.node))
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace(
|
||||
"Bypass src guard while moving from %s to %s",
|
||||
source.coord.toString(),
|
||||
destination.coord.toString());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
destination.blocked = true;
|
||||
}
|
||||
}
|
||||
35
AI/VCAI/Pathfinding/Rules/AIMovementToDestinationRule.h
Normal file
35
AI/VCAI/Pathfinding/Rules/AIMovementToDestinationRule.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* AIMovementToDestinationRule.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../AINodeStorage.h"
|
||||
#include "../../VCAI.h"
|
||||
#include "../../../../CCallback.h"
|
||||
#include "../../../../lib/mapping/CMap.h"
|
||||
#include "../../../../lib/mapObjects/MapObjects.h"
|
||||
|
||||
namespace AIPathfinding
|
||||
{
|
||||
class AIMovementToDestinationRule : public MovementToDestinationRule
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<AINodeStorage> nodeStorage;
|
||||
|
||||
public:
|
||||
AIMovementToDestinationRule(std::shared_ptr<AINodeStorage> nodeStorage);
|
||||
|
||||
virtual void process(
|
||||
const PathNodeInfo & source,
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathfinderConfig * pathfinderConfig,
|
||||
CPathfinderHelper * pathfinderHelper) const override;
|
||||
};
|
||||
}
|
||||
47
AI/VCAI/Pathfinding/Rules/AIPreviousNodeRule.cpp
Normal file
47
AI/VCAI/Pathfinding/Rules/AIPreviousNodeRule.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* AIPreviousNodeRule.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "AIPreviousNodeRule.h"
|
||||
|
||||
namespace AIPathfinding
|
||||
{
|
||||
AIPreviousNodeRule::AIPreviousNodeRule(std::shared_ptr<AINodeStorage> nodeStorage)
|
||||
: nodeStorage(nodeStorage)
|
||||
{
|
||||
}
|
||||
|
||||
void AIPreviousNodeRule::process(
|
||||
const PathNodeInfo & source,
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathfinderConfig * pathfinderConfig,
|
||||
CPathfinderHelper * pathfinderHelper) const
|
||||
{
|
||||
if(source.node->action == CGPathNode::ENodeAction::BLOCKING_VISIT || source.node->action == CGPathNode::ENodeAction::VISIT)
|
||||
{
|
||||
// we can not directly bypass objects, we need to interact with them first
|
||||
destination.node->theNodeBefore = source.node;
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace(
|
||||
"Link src node %s to destination node %s while bypassing visitable obj",
|
||||
source.coord.toString(),
|
||||
destination.coord.toString());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
auto aiSourceNode = nodeStorage->getAINode(source.node);
|
||||
|
||||
if(aiSourceNode->specialAction)
|
||||
{
|
||||
// there is some action on source tile which should be performed before we can bypass it
|
||||
destination.node->theNodeBefore = source.node;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
AI/VCAI/Pathfinding/Rules/AIPreviousNodeRule.h
Normal file
35
AI/VCAI/Pathfinding/Rules/AIPreviousNodeRule.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* AIPreviousNodeRule.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../AINodeStorage.h"
|
||||
#include "../../VCAI.h"
|
||||
#include "../../../../CCallback.h"
|
||||
#include "../../../../lib/mapping/CMap.h"
|
||||
#include "../../../../lib/mapObjects/MapObjects.h"
|
||||
|
||||
namespace AIPathfinding
|
||||
{
|
||||
class AIPreviousNodeRule : public MovementToDestinationRule
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<AINodeStorage> nodeStorage;
|
||||
|
||||
public:
|
||||
AIPreviousNodeRule(std::shared_ptr<AINodeStorage> nodeStorage);
|
||||
|
||||
virtual void process(
|
||||
const PathNodeInfo & source,
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathfinderConfig * pathfinderConfig,
|
||||
CPathfinderHelper * pathfinderHelper) const override;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user