| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | /*
 | 
					
						
							|  |  |  | * ExecuteHeroChain.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 "ExecuteHeroChain.h"
 | 
					
						
							|  |  |  | #include "VisitTile.h"
 | 
					
						
							|  |  |  | #include "../VCAI.h"
 | 
					
						
							|  |  |  | #include "../FuzzyHelper.h"
 | 
					
						
							|  |  |  | #include "../AIhelper.h"
 | 
					
						
							| 
									
										
										
										
											2021-05-15 21:57:44 +03:00
										 |  |  | #include "../../../lib/mapping/CMap.h" //for victory conditions
 | 
					
						
							|  |  |  | #include "../../../lib/CPathfinder.h"
 | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | #include "../Engine/Nullkiller.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern boost::thread_specific_ptr<CCallback> cb; | 
					
						
							|  |  |  | extern boost::thread_specific_ptr<VCAI> ai; | 
					
						
							|  |  |  | extern FuzzyHelper * fh; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace Goals; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ExecuteHeroChain::ExecuteHeroChain(const AIPath & path, const CGObjectInstance * obj) | 
					
						
							| 
									
										
										
										
											2021-05-16 14:38:26 +03:00
										 |  |  | 	:ElementarGoal(Goals::EXECUTE_HERO_CHAIN), chainPath(path) | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-05-16 14:14:07 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | 	hero = path.targetHero; | 
					
						
							| 
									
										
										
										
											2021-05-15 21:57:27 +03:00
										 |  |  | 	tile = path.targetTile(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(obj) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		objid = obj->id.getNum(); | 
					
						
							|  |  |  | 		targetName = obj->getObjectName() + tile.toString(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		targetName = "tile" + tile.toString(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ExecuteHeroChain::operator==(const ExecuteHeroChain & other) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ExecuteHeroChain::accept(VCAI * ai) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-05-15 21:57:27 +03:00
										 |  |  | 	logAi->debug("Executing hero chain towards %s. Path %s", targetName, chainPath.toString()); | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 14:38:26 +03:00
										 |  |  | 	ai->nullkiller->setActive(chainPath.targetHero, tile); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | 	std::set<int> blockedIndexes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(int i = chainPath.nodes.size() - 1; i >= 0; i--) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		auto & node = chainPath.nodes[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 		const CGHeroInstance * hero = node.targetHero; | 
					
						
							|  |  |  | 		HeroPtr heroPtr = hero; | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if(vstd::contains(blockedIndexes, i)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			blockedIndexes.insert(node.parentIndex); | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 			ai->nullkiller->lockHero(hero, HeroLockedReason::HERO_CHAIN); | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 		logAi->debug("Executing chain node %d. Moving hero %s to %s", i, hero->name, node.coord.toString()); | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		try | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2021-05-15 22:02:27 +03:00
										 |  |  | 			if(hero->movement) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 				ai->nullkiller->setActive(hero, node.coord); | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-15 22:02:57 +03:00
										 |  |  | 				if(node.specialAction) | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 					if(node.specialAction->canAct(hero)) | 
					
						
							| 
									
										
										
										
											2021-05-16 14:07:54 +03:00
										 |  |  | 					{ | 
					
						
							|  |  |  | 						auto specialGoal = node.specialAction->whatToDo(hero); | 
					
						
							| 
									
										
										
										
											2021-05-15 22:02:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 14:38:26 +03:00
										 |  |  | 						if(!specialGoal->isElementar) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 14:19:27 +03:00
										 |  |  | 						specialGoal->accept(ai); | 
					
						
							| 
									
										
										
										
											2021-05-16 14:07:54 +03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					else | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 						throw cannotFulfillGoalException("Path is nondeterministic."); | 
					
						
							| 
									
										
										
										
											2021-05-16 14:07:54 +03:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 					 | 
					
						
							|  |  |  | 					if(!heroPtr.validAndSet()) | 
					
						
							| 
									
										
										
										
											2021-05-16 14:19:44 +03:00
										 |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 						logAi->error("Hero %s was lost trying to execute special action. Exit hero chain.", heroPtr.name); | 
					
						
							| 
									
										
										
										
											2021-05-16 14:19:44 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						return; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2021-05-15 22:02:57 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 14:19:07 +03:00
										 |  |  | 				if(node.turns == 0 && node.coord != hero->visitablePos()) | 
					
						
							| 
									
										
										
										
											2021-05-16 14:09:49 +03:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 					auto targetNode = cb->getPathsInfo(hero)->getPathInfo(node.coord); | 
					
						
							| 
									
										
										
										
											2021-05-16 14:09:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 14:19:44 +03:00
										 |  |  | 					if(targetNode->accessible == CGPathNode::EAccessibility::NOT_SET | 
					
						
							|  |  |  | 						|| targetNode->accessible == CGPathNode::EAccessibility::BLOCKED | 
					
						
							|  |  |  | 						|| targetNode->accessible == CGPathNode::EAccessibility::FLYABLE | 
					
						
							|  |  |  | 						|| targetNode->turns != 0) | 
					
						
							| 
									
										
										
										
											2021-05-16 14:09:49 +03:00
										 |  |  | 					{ | 
					
						
							|  |  |  | 						logAi->error( | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:48 +03:00
										 |  |  | 							"Enable to complete chain. Expected hero %s to arive to %s in 0 turns but he can not do this", | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 							hero->name, | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:48 +03:00
										 |  |  | 							node.coord.toString()); | 
					
						
							| 
									
										
										
										
											2021-05-16 14:09:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						return; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:48 +03:00
										 |  |  | 				if(hero->movement) | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:40 +03:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:48 +03:00
										 |  |  | 					try | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:40 +03:00
										 |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-05-16 14:38:26 +03:00
										 |  |  | 						if(moveHeroToTile(hero, node.coord)) | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							continue; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:48 +03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					catch(cannotFulfillGoalException) | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 						if(!heroPtr.validAndSet()) | 
					
						
							| 
									
										
										
										
											2021-05-16 14:19:44 +03:00
										 |  |  | 						{ | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 							logAi->error("Hero %s was lost. Exit hero chain.", heroPtr.name); | 
					
						
							| 
									
										
										
										
											2021-05-16 14:19:44 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							return; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:48 +03:00
										 |  |  | 						if(hero->movement > 0) | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:40 +03:00
										 |  |  | 						{ | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:48 +03:00
										 |  |  | 							CGPath path; | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 							bool isOk = cb->getPathsInfo(hero)->getPath(path, node.coord); | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:48 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							if(isOk && path.nodes.back().turns > 0) | 
					
						
							|  |  |  | 							{ | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 								logAi->warn("Hero %s has %d mp which is not enough to continue his way towards %s.", hero->name, hero->movement, node.coord.toString()); | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:40 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 								ai->nullkiller->lockHero(hero, HeroLockedReason::HERO_CHAIN); | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:48 +03:00
										 |  |  | 								return; | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:40 +03:00
										 |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:48 +03:00
										 |  |  | 						throw; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:40 +03:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-05-15 22:02:27 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-05-15 21:57:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 14:19:07 +03:00
										 |  |  | 			if(node.coord == hero->visitablePos()) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 14:09:49 +03:00
										 |  |  | 			if(node.turns == 0) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				logAi->error( | 
					
						
							|  |  |  | 					"Enable to complete chain. Expected hero %s to arive to %s but he is at %s",  | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 					hero->name,  | 
					
						
							| 
									
										
										
										
											2021-05-16 14:09:49 +03:00
										 |  |  | 					node.coord.toString(), | 
					
						
							|  |  |  | 					hero->visitablePos().toString()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-05-16 14:13:56 +03:00
										 |  |  | 			 | 
					
						
							| 
									
										
										
										
											2021-05-15 21:57:27 +03:00
										 |  |  | 			// no exception means we were not able to rich the tile
 | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 			ai->nullkiller->lockHero(hero, HeroLockedReason::HERO_CHAIN); | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | 			blockedIndexes.insert(node.parentIndex); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		catch(goalFulfilledException) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 			if(!heroPtr.validAndSet()) | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2019-12-15 15:47:21 +02:00
										 |  |  | 				logAi->debug("Hero %s was killed while attempting to rich %s", heroPtr.name, node.coord.toString()); | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 14:38:26 +03:00
										 |  |  | std::string ExecuteHeroChain::toString() const | 
					
						
							| 
									
										
										
										
											2021-05-15 21:56:31 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-05-16 14:15:03 +03:00
										 |  |  | 	return "ExecuteHeroChain " + targetName + " by " + chainPath.targetHero->name; | 
					
						
							| 
									
										
										
										
											2021-05-16 14:38:26 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ExecuteHeroChain::moveHeroToTile(const CGHeroInstance * hero, const int3 & tile) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if(g.tile == g.hero->visitablePos() && cb->getVisitableObjs(g.hero->visitablePos()).size() < 2) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", g.hero->name, g.tile.toString()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ai->moveHeroToTile(tile, hero); | 
					
						
							| 
									
										
										
										
											2021-05-15 22:02:52 +03:00
										 |  |  | } |