PotentialTargets.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /*
  2. * PotentialTargets.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 "PotentialTargets.h"
  12. #include "../../lib/CStack.h"//todo: remove
  13. PotentialTargets::PotentialTargets(
  14. const battle::Unit * attacker,
  15. DamageCache & damageCache,
  16. std::shared_ptr<HypotheticBattle> state)
  17. {
  18. auto attackerInfo = state->battleGetUnitByID(attacker->unitId());
  19. auto reachability = state->getReachability(attackerInfo);
  20. auto avHexes = state->battleGetAvailableHexes(reachability, attackerInfo, false);
  21. //FIXME: this should part of battleGetAvailableHexes
  22. bool forceTarget = false;
  23. const battle::Unit * forcedTarget = nullptr;
  24. BattleHex forcedHex;
  25. if(attackerInfo->hasBonusOfType(BonusType::ATTACKS_NEAREST_CREATURE))
  26. {
  27. forceTarget = true;
  28. auto nearest = state->getNearestStack(attackerInfo);
  29. if(nearest.first != nullptr)
  30. {
  31. forcedTarget = nearest.first;
  32. forcedHex = nearest.second;
  33. }
  34. }
  35. auto aliveUnits = state->battleGetUnitsIf([=](const battle::Unit * unit)
  36. {
  37. return unit->isValidTarget() && unit->unitId() != attackerInfo->unitId();
  38. });
  39. for(auto defender : aliveUnits)
  40. {
  41. if(!forceTarget && !state->battleMatchOwner(attackerInfo, defender))
  42. continue;
  43. auto GenerateAttackInfo = [&](bool shooting, BattleHex hex) -> AttackPossibility
  44. {
  45. int distance = hex.isValid() ? reachability.distances[hex] : 0;
  46. auto bai = BattleAttackInfo(attackerInfo, defender, distance, shooting);
  47. return AttackPossibility::evaluate(bai, hex, damageCache, state);
  48. };
  49. if(forceTarget)
  50. {
  51. if(forcedTarget && defender->unitId() == forcedTarget->unitId())
  52. possibleAttacks.push_back(GenerateAttackInfo(false, forcedHex));
  53. else
  54. unreachableEnemies.push_back(defender);
  55. }
  56. else if(state->battleCanShoot(attackerInfo, defender->getPosition()))
  57. {
  58. possibleAttacks.push_back(GenerateAttackInfo(true, BattleHex::INVALID));
  59. }
  60. else
  61. {
  62. for(BattleHex hex : avHexes)
  63. {
  64. if(!CStack::isMeleeAttackPossible(attackerInfo, defender, hex))
  65. continue;
  66. auto bai = GenerateAttackInfo(false, hex);
  67. if(!bai.affectedUnits.empty())
  68. possibleAttacks.push_back(bai);
  69. }
  70. if(!vstd::contains_if(possibleAttacks, [=](const AttackPossibility & pa) { return pa.attack.defender->unitId() == defender->unitId(); }))
  71. unreachableEnemies.push_back(defender);
  72. }
  73. }
  74. boost::sort(possibleAttacks, [](const AttackPossibility & lhs, const AttackPossibility & rhs) -> bool
  75. {
  76. return lhs.damageDiff() > rhs.damageDiff();
  77. });
  78. }
  79. int64_t PotentialTargets::bestActionValue() const
  80. {
  81. if(possibleAttacks.empty())
  82. return 0;
  83. return bestAction().attackValue();
  84. }
  85. const AttackPossibility & PotentialTargets::bestAction() const
  86. {
  87. if(possibleAttacks.empty())
  88. throw std::runtime_error("No best action, since we don't have any actions");
  89. return possibleAttacks.front();
  90. }