CaptureObjectsBehavior.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * CaptureObjectsBehavior.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "../VCAI.h"
  12. #include "../Engine/Nullkiller.h"
  13. #include "../AIhelper.h"
  14. #include "../Goals/Composition.h"
  15. #include "../Goals/ExecuteHeroChain.h"
  16. #include "CaptureObjectsBehavior.h"
  17. #include "../AIUtility.h"
  18. #include "../../../lib/mapping/CMap.h" //for victory conditions
  19. #include "../../../lib/CPathfinder.h"
  20. extern boost::thread_specific_ptr<CCallback> cb;
  21. extern boost::thread_specific_ptr<VCAI> ai;
  22. extern FuzzyHelper * fh;
  23. using namespace Goals;
  24. template <typename T>
  25. bool vectorEquals(const std::vector<T> & v1, const std::vector<T> & v2)
  26. {
  27. return vstd::contains_if(v1, [&](T o) -> bool
  28. {
  29. return vstd::contains(v2, o);
  30. });
  31. }
  32. std::string CaptureObjectsBehavior::toString() const
  33. {
  34. return "Capture objects";
  35. }
  36. bool CaptureObjectsBehavior::operator==(const CaptureObjectsBehavior & other) const
  37. {
  38. if(specificObjects != other.specificObjects)
  39. return false;
  40. if(specificObjects)
  41. return vectorEquals(objectsToCapture, other.objectsToCapture);
  42. return vectorEquals(objectTypes, other.objectTypes)
  43. && vectorEquals(objectSubTypes, other.objectSubTypes);
  44. }
  45. Goals::TGoalVec CaptureObjectsBehavior::getVisitGoals(const std::vector<AIPath> & paths, const CGObjectInstance * objToVisit)
  46. {
  47. Goals::TGoalVec tasks;
  48. tasks.reserve(paths.size());
  49. const AIPath * closestWay = nullptr;
  50. std::vector<ExecuteHeroChain *> waysToVisitObj;
  51. for(auto & path : paths)
  52. {
  53. tasks.push_back(sptr(Goals::Invalid()));
  54. #if AI_TRACE_LEVEL >= 2
  55. logAi->trace("Path found %s", path.toString());
  56. #endif
  57. if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
  58. {
  59. #if AI_TRACE_LEVEL >= 2
  60. logAi->trace("Ignore path. Target hero can be killed by enemy. Our power %lld", path.heroArmy->getArmyStrength());
  61. #endif
  62. continue;
  63. }
  64. if(objToVisit && !shouldVisit(path.targetHero, objToVisit))
  65. continue;
  66. auto hero = path.targetHero;
  67. auto danger = path.getTotalDanger();
  68. if(ai->ah->getHeroRole(hero) == HeroRole::SCOUT && danger == 0 && path.exchangeCount > 1)
  69. continue;
  70. auto firstBlockedAction = path.getFirstBlockedAction();
  71. if(firstBlockedAction)
  72. {
  73. auto subGoal = firstBlockedAction->decompose(path.targetHero);
  74. #if AI_TRACE_LEVEL >= 2
  75. logAi->trace("Decomposing special action %s returns %s", firstBlockedAction->toString(), subGoal->toString());
  76. #endif
  77. if(!subGoal->invalid())
  78. {
  79. Composition composition;
  80. composition.addNext(ExecuteHeroChain(path, objToVisit));
  81. composition.addNext(subGoal);
  82. tasks[tasks.size() - 1] = sptr(composition);
  83. }
  84. continue;
  85. }
  86. auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);
  87. #if AI_TRACE_LEVEL >= 2
  88. logAi->trace(
  89. "It is %s to visit %s by %s with army %lld, danger %lld and army loss %lld",
  90. isSafe ? "safe" : "not safe",
  91. objToVisit ? objToVisit->getObjectName() : path.targetTile().toString(),
  92. hero->name,
  93. path.getHeroStrength(),
  94. danger,
  95. path.getTotalArmyLoss());
  96. #endif
  97. if(isSafe)
  98. {
  99. auto newWay = new ExecuteHeroChain(path, objToVisit);
  100. TSubgoal sharedPtr;
  101. sharedPtr.reset(newWay);
  102. if(!closestWay || closestWay->movementCost() > path.movementCost())
  103. closestWay = &path;
  104. if(!ai->nullkiller->arePathHeroesLocked(path))
  105. {
  106. waysToVisitObj.push_back(newWay);
  107. tasks[tasks.size() - 1] = sharedPtr;
  108. }
  109. }
  110. }
  111. for(auto way : waysToVisitObj)
  112. {
  113. way->closestWayRatio
  114. = closestWay->movementCost() / way->getPath().movementCost();
  115. }
  116. return tasks;
  117. }
  118. Goals::TGoalVec CaptureObjectsBehavior::decompose() const
  119. {
  120. Goals::TGoalVec tasks;
  121. auto captureObjects = [&](const std::vector<const CGObjectInstance*> & objs) -> void{
  122. if(objs.empty())
  123. {
  124. return;
  125. }
  126. logAi->debug("Scanning objects, count %d", objs.size());
  127. for(auto objToVisit : objs)
  128. {
  129. #if AI_TRACE_LEVEL >= 1
  130. logAi->trace("Checking object %s, %s", objToVisit->getObjectName(), objToVisit->visitablePos().toString());
  131. #endif
  132. if(!shouldVisitObject(objToVisit))
  133. continue;
  134. const int3 pos = objToVisit->visitablePos();
  135. auto paths = ai->ah->getPathsToTile(pos);
  136. std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;
  137. std::shared_ptr<ExecuteHeroChain> closestWay;
  138. #if AI_TRACE_LEVEL >= 1
  139. logAi->trace("Found %d paths", paths.size());
  140. #endif
  141. vstd::concatenate(tasks, getVisitGoals(paths, objToVisit));
  142. }
  143. vstd::erase_if(tasks, [](TSubgoal task) -> bool
  144. {
  145. return task->invalid();
  146. });
  147. };
  148. if(specificObjects)
  149. {
  150. captureObjects(objectsToCapture);
  151. }
  152. else
  153. {
  154. captureObjects(ai->nullkiller->objectClusterizer->getNearbyObjects());
  155. if(tasks.empty())
  156. captureObjects(ai->nullkiller->objectClusterizer->getFarObjects());
  157. }
  158. return tasks;
  159. }
  160. bool CaptureObjectsBehavior::shouldVisitObject(const CGObjectInstance * obj) const
  161. {
  162. if(objectTypes.size() && !vstd::contains(objectTypes, obj->ID.num))
  163. {
  164. return false;
  165. }
  166. if(objectSubTypes.size() && !vstd::contains(objectSubTypes, obj->subID))
  167. {
  168. return false;
  169. }
  170. return true;
  171. }