| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 | 
							- /*
 
- * 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"
 
- #include "../../../../lib/pathfinder/CPathfinder.h"
 
- #include "../../../../lib/pathfinder/TurnInfo.h"
 
- namespace NKAI
 
- {
 
- namespace AIPathfinding
 
- {
 
- 	AILayerTransitionRule::AILayerTransitionRule(
 
- 		CPlayerSpecificInfoCallback * cb,
 
- 		Nullkiller * 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 NKAI_PATHFINDER_TRACE_LEVEL >= 2
 
- 		logAi->trace("Layer transitioning %s -> %s, action: %d, blocked: %s",
 
- 			source.coord.toString(),
 
- 			destination.coord.toString(),
 
- 			static_cast<int32_t>(destination.action),
 
- 			destination.blocked ? "true" : "false");
 
- #endif
 
- 		if(!destination.blocked)
 
- 		{
 
- 			if(source.node->layer == EPathfindingLayer::LAND
 
- 				&& (destination.node->layer == EPathfindingLayer::AIR || destination.node->layer == EPathfindingLayer::WATER))
 
- 			{
 
- 				if(pathfinderHelper->getTurnInfo()->isLayerAvailable(destination.node->layer))
 
- 					return;
 
- 				else
 
- 					destination.blocked = true;
 
- 			}
 
- 			else
 
- 			{
 
- 				return;
 
- 			}
 
- 		}
 
- 		if(source.node->layer == EPathfindingLayer::LAND && destination.node->layer == EPathfindingLayer::SAIL)
 
- 		{
 
- 			std::shared_ptr<const VirtualBoatAction> virtualBoat = findVirtualBoat(destination, source);
 
- 			if(virtualBoat && tryUseSpecialAction(destination, source, virtualBoat, EPathNodeAction::EMBARK))
 
- 			{
 
- #if NKAI_PATHFINDER_TRACE_LEVEL >= 1
 
- 				logAi->trace("Embarking to virtual boat while moving %s -> %s!", source.coord.toString(), destination.coord.toString());
 
- #endif
 
- 			}
 
- 		}
 
- 		if(source.node->layer == EPathfindingLayer::LAND && destination.node->layer == EPathfindingLayer::WATER)
 
- 		{
 
- 			if(nodeStorage->getAINode(source.node)->dayFlags & DayFlags::WATER_WALK_CAST)
 
- 			{
 
- 				destination.blocked = false;
 
- 				return;
 
- 			}
 
- 			auto action = waterWalkingActions.find(nodeStorage->getHero(source.node));
 
- 			if(action != waterWalkingActions.end() && tryUseSpecialAction(destination, source, action->second, EPathNodeAction::NORMAL))
 
- 			{
 
- #if NKAI_PATHFINDER_TRACE_LEVEL >= 2
 
- 				logAi->trace("Casting water walk while moving %s -> %s!", source.coord.toString(), destination.coord.toString());
 
- #endif
 
- 			}
 
- 		}
 
- 		if(source.node->layer == EPathfindingLayer::LAND && destination.node->layer == EPathfindingLayer::AIR)
 
- 		{
 
- 			if(nodeStorage->getAINode(source.node)->dayFlags & DayFlags::FLY_CAST)
 
- 			{
 
- 				destination.blocked = false;
 
- 				return;
 
- 			}
 
- 			auto action = airWalkingActions.find(nodeStorage->getHero(source.node));
 
- 			if(action != airWalkingActions.end() && tryUseSpecialAction(destination, source, action->second, EPathNodeAction::NORMAL))
 
- 			{
 
- #if NKAI_PATHFINDER_TRACE_LEVEL >= 2
 
- 				logAi->trace("Casting fly while moving %s -> %s!", source.coord.toString(), destination.coord.toString());
 
- #endif
 
- 			}
 
- 		}
 
- 	}
 
- 	void AILayerTransitionRule::setup()
 
- 	{
 
- 		SpellID waterWalk = SpellID::WATER_WALK;
 
- 		SpellID airWalk = SpellID::FLY;
 
- 		for(const CGHeroInstance * hero : nodeStorage->getAllHeroes())
 
- 		{
 
- 			if(hero->canCastThisSpell(waterWalk.toSpell()) && hero->mana >= hero->getSpellCost(waterWalk.toSpell()))
 
- 			{
 
- 				waterWalkingActions[hero] = std::make_shared<WaterWalkingAction>(hero);
 
- 			}
 
- 			if(hero->canCastThisSpell(airWalk.toSpell()) && hero->mana >= hero->getSpellCost(airWalk.toSpell()))
 
- 			{
 
- 				airWalkingActions[hero] = std::make_shared<AirWalkingAction>(hero);
 
- 			}
 
- 		}
 
- 		collectVirtualBoats();
 
- 	}
 
- 	void AILayerTransitionRule::collectVirtualBoats()
 
- 	{
 
- 		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)
 
- 		{
 
- 			if(obj->ID != Obj::TOWN) //towns were handled in the previous loop
 
- 			{
 
- 				if(const auto * shipyard = dynamic_cast<const IShipyard *>(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);
 
- 				logAi->debug("Virtual boat added at %s", boatLocation.toString());
 
- 			}
 
- 		}
 
- 		for(const CGHeroInstance * hero : nodeStorage->getAllHeroes())
 
- 		{
 
- 			auto summonBoatSpell = SpellID(SpellID::SUMMON_BOAT).toSpell();
 
- 			if(hero->canCastThisSpell(summonBoatSpell)
 
- 				&& hero->getSpellSchoolLevel(summonBoatSpell) >= MasteryLevel::ADVANCED)
 
- 			{
 
- 				// TODO: For lower school level we might need to check the existence of some boat
 
- 				summonableVirtualBoats[hero] = std::make_shared<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
 
- 		{
 
- 			const CGHeroInstance * hero = nodeStorage->getHero(source.node);
 
- 			if(vstd::contains(summonableVirtualBoats, hero)
 
- 				&& summonableVirtualBoats.at(hero)->canAct(ai, nodeStorage->getAINode(source.node)))
 
- 			{
 
- 				virtualBoat = summonableVirtualBoats.at(hero);
 
- 			}
 
- 		}
 
- 		return virtualBoat;
 
- 	}
 
- 	bool AILayerTransitionRule::tryUseSpecialAction(
 
- 		CDestinationNodeInfo & destination,
 
- 		const PathNodeInfo & source,
 
- 		std::shared_ptr<const SpecialAction> specialAction,
 
- 		EPathNodeAction targetAction) const
 
- 	{
 
- 		bool result = false;
 
- 		nodeStorage->updateAINode(destination.node, [&](AIPathNode * node)
 
- 			{
 
- 				auto castNodeOptional = nodeStorage->getOrCreateNode(
 
- 					node->coord,
 
- 					node->layer,
 
- 					specialAction->getActor(node->actor));
 
- 				if(castNodeOptional)
 
- 				{
 
- 					AIPathNode * castNode = castNodeOptional.value();
 
- 					if(castNode->action == EPathNodeAction::UNKNOWN)
 
- 					{
 
- 						castNode->addSpecialAction(specialAction);
 
- 						destination.blocked = false;
 
- 						destination.action = targetAction;
 
- 						destination.node = castNode;
 
- 						result = true;
 
- 					}
 
- 					else
 
- 					{
 
- #if NKAI_PATHFINDER_TRACE_LEVEL >= 1
 
- 						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;
 
- 	}
 
- }
 
- }
 
 
  |