1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00
vcmi/AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp

162 lines
4.3 KiB
C++
Raw Normal View History

2021-05-15 18:22:44 +02:00
/*
* 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"
#include "../../Engine/Nullkiller.h"
2021-05-15 18:22:44 +02:00
namespace AIPathfinding
{
AILayerTransitionRule::AILayerTransitionRule(CPlayerSpecificInfoCallback * cb, Nullkiller * ai, std::shared_ptr<AINodeStorage> nodeStorage)
2021-05-15 18:22:44 +02:00
: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))
{
#if PATHFINDER_TRACE_LEVEL >= 1
2021-05-15 18:22:44 +02:00
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->memory->visitableObjs)
2021-05-15 18:22:44 +02:00
{
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>(cb, shipyard);
2021-05-15 18:22:44 +02:00
logAi->debug("Virtual boat added at %s", boatLocation.toString());
}
}
2021-05-15 18:22:49 +02:00
for(const CGHeroInstance * hero : nodeStorage->getAllHeroes())
2021-05-15 18:22:44 +02:00
{
2021-05-15 18:22:49 +02:00
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
summonableVirtualBoats[hero] = std::make_shared<SummonBoatAction>();
}
2021-05-15 18:22:44 +02:00
}
}
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);
}
2021-05-15 18:22:49 +02:00
else
2021-05-15 18:22:44 +02:00
{
2021-05-15 18:22:49 +02:00
const CGHeroInstance * hero = nodeStorage->getHero(source.node);
if(vstd::contains(summonableVirtualBoats, hero)
2021-05-16 13:38:53 +02:00
&& summonableVirtualBoats.at(hero)->canAct(nodeStorage->getAINode(source.node)))
2021-05-15 18:22:49 +02:00
{
virtualBoat = summonableVirtualBoats.at(hero);
}
2021-05-15 18:22:44 +02:00
}
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,
2021-05-15 18:22:49 +02:00
virtualBoat->getActor(node->actor));
2021-05-15 18:22:44 +02:00
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
{
#if PATHFINDER_TRACE_LEVEL >= 1
2021-05-15 18:22:44 +02:00
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;
}
}