AIMovementAfterDestinationRule.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * AIMovementAfterDestinationRule.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 "AIMovementAfterDestinationRule.h"
  12. #include "../Actions/BattleAction.h"
  13. namespace AIPathfinding
  14. {
  15. AIMovementAfterDestinationRule::AIMovementAfterDestinationRule(
  16. CPlayerSpecificInfoCallback * cb,
  17. std::shared_ptr<AINodeStorage> nodeStorage)
  18. :cb(cb), nodeStorage(nodeStorage)
  19. {
  20. }
  21. void AIMovementAfterDestinationRule::process(
  22. const PathNodeInfo & source,
  23. CDestinationNodeInfo & destination,
  24. const PathfinderConfig * pathfinderConfig,
  25. CPathfinderHelper * pathfinderHelper) const
  26. {
  27. if(nodeStorage->hasBetterChain(source, destination))
  28. {
  29. destination.blocked = true;
  30. return;
  31. }
  32. auto blocker = getBlockingReason(source, destination, pathfinderConfig, pathfinderHelper);
  33. if(blocker == BlockingReason::NONE)
  34. return;
  35. if(blocker == BlockingReason::DESTINATION_BLOCKVIS && destination.nodeObject)
  36. {
  37. auto enemyHero = destination.nodeHero && destination.heroRelations == PlayerRelations::ENEMIES;
  38. if(!enemyHero && !isObjectRemovable(destination.nodeObject))
  39. {
  40. if(nodeStorage->getHero(destination.node) == destination.nodeHero)
  41. return;
  42. destination.blocked = true;
  43. }
  44. return;
  45. }
  46. if(blocker == BlockingReason::DESTINATION_VISIT)
  47. {
  48. return;
  49. }
  50. if(blocker == BlockingReason::DESTINATION_GUARDED)
  51. {
  52. auto srcGuardians = cb->getGuardingCreatures(source.coord);
  53. auto destGuardians = cb->getGuardingCreatures(destination.coord);
  54. if(destGuardians.empty())
  55. {
  56. destination.blocked = true;
  57. return;
  58. }
  59. vstd::erase_if(destGuardians, [&](const CGObjectInstance * destGuard) -> bool
  60. {
  61. return vstd::contains(srcGuardians, destGuard);
  62. });
  63. auto guardsAlreadyBypassed = destGuardians.empty() && srcGuardians.size();
  64. auto srcNode = nodeStorage->getAINode(source.node);
  65. if(guardsAlreadyBypassed && srcNode->actor->allowBattle)
  66. {
  67. #ifdef VCMI_TRACE_PATHFINDER
  68. logAi->trace(
  69. "Bypass guard at destination while moving %s -> %s",
  70. source.coord.toString(),
  71. destination.coord.toString());
  72. #endif
  73. return;
  74. }
  75. const AIPathNode * destNode = nodeStorage->getAINode(destination.node);
  76. auto battleNodeOptional = nodeStorage->getOrCreateNode(
  77. destination.coord,
  78. destination.node->layer,
  79. destNode->actor->battleActor);
  80. if(!battleNodeOptional)
  81. {
  82. #ifdef VCMI_TRACE_PATHFINDER
  83. logAi->trace(
  84. "Can not allocate battle node while moving %s -> %s",
  85. source.coord.toString(),
  86. destination.coord.toString());
  87. #endif
  88. destination.blocked = true;
  89. return;
  90. }
  91. AIPathNode * battleNode = battleNodeOptional.get();
  92. if(battleNode->locked)
  93. {
  94. #ifdef VCMI_TRACE_PATHFINDER
  95. logAi->trace(
  96. "Block bypass guard at destination while moving %s -> %s",
  97. source.coord.toString(),
  98. destination.coord.toString());
  99. #endif
  100. destination.blocked = true;
  101. return;
  102. }
  103. auto hero = nodeStorage->getHero(source.node);
  104. auto danger = nodeStorage->evaluateDanger(destination.coord, hero);
  105. double actualArmyValue = srcNode->actor->armyValue - srcNode->armyLoss;
  106. double ratio = (double)danger / (actualArmyValue * hero->getFightingStrength());
  107. uint64_t loss = (uint64_t)(actualArmyValue * ratio * ratio * ratio);
  108. if(loss < actualArmyValue)
  109. {
  110. destination.node = battleNode;
  111. nodeStorage->commit(destination, source);
  112. battleNode->armyLoss += loss;
  113. vstd::amax(battleNode->danger, danger);
  114. battleNode->specialAction = std::make_shared<BattleAction>(destination.coord);
  115. #ifdef VCMI_TRACE_PATHFINDER
  116. logAi->trace(
  117. "Begin bypass guard at destination with danger %s while moving %s -> %s",
  118. std::to_string(danger),
  119. source.coord.toString(),
  120. destination.coord.toString());
  121. #endif
  122. return;
  123. }
  124. }
  125. destination.blocked = true;
  126. }
  127. }